@@ -311,7 +311,7 @@ static int elf_exec_load(struct kimage *image, struct elfhdr *ehdr,
(char *) elf_info->buffer + phdr->p_offset,
size, phdr->p_memsz, phdr->p_align,
phdr->p_paddr + base, ppc64_rma_size,
- false, &load_addr);
+ false, true, &load_addr);
if (ret)
goto out;
@@ -487,7 +487,7 @@ void *elf64_load(struct kimage *image, char *kernel_buf,
if (initrd != NULL) {
ret = kexec_add_buffer(image, initrd, initrd_len, initrd_len,
PAGE_SIZE, 0, ppc64_rma_size, false,
- &initrd_load_addr);
+ true, &initrd_load_addr);
if (ret)
goto out;
@@ -564,7 +564,7 @@ void *elf64_load(struct kimage *image, char *kernel_buf,
fdt_pack(fdt);
ret = kexec_add_buffer(image, fdt, fdt_size, fdt_size, PAGE_SIZE, 0,
- ppc64_rma_size, true, &fdt_load_addr);
+ ppc64_rma_size, true, true, &fdt_load_addr);
if (ret)
goto out;
@@ -643,7 +643,7 @@ int crash_load_segments(struct kimage *image)
*/
ret = kexec_add_buffer(image, (char *)&crash_zero_bytes,
sizeof(crash_zero_bytes), src_sz,
- PAGE_SIZE, 0, -1, 0,
+ PAGE_SIZE, 0, -1, false, true,
&image->arch.backup_load_addr);
if (ret)
return ret;
@@ -660,7 +660,7 @@ int crash_load_segments(struct kimage *image)
image->arch.elf_headers_sz = elf_sz;
ret = kexec_add_buffer(image, (char *)elf_addr, elf_sz, elf_sz,
- ELF_CORE_HEADER_ALIGN, 0, -1, 0,
+ ELF_CORE_HEADER_ALIGN, 0, -1, false, true,
&image->arch.elf_load_addr);
if (ret) {
vfree((void *)image->arch.elf_headers);
@@ -420,7 +420,7 @@ static void *bzImage64_load(struct kimage *image, char *kernel,
ret = kexec_add_buffer(image, (char *)params, params_misc_sz,
params_misc_sz, 16, MIN_BOOTPARAM_ADDR,
- ULONG_MAX, 1, &bootparam_load_addr);
+ ULONG_MAX, true, true, &bootparam_load_addr);
if (ret)
goto out_free_params;
pr_debug("Loaded boot_param, command line and misc at 0x%lx bufsz=0x%lx memsz=0x%lx\n",
@@ -434,7 +434,7 @@ static void *bzImage64_load(struct kimage *image, char *kernel,
ret = kexec_add_buffer(image, kernel_buf,
kernel_bufsz, kernel_memsz, kernel_align,
- MIN_KERNEL_LOAD_ADDR, ULONG_MAX, 1,
+ MIN_KERNEL_LOAD_ADDR, ULONG_MAX, true, true,
&kernel_load_addr);
if (ret)
goto out_free_params;
@@ -446,7 +446,7 @@ static void *bzImage64_load(struct kimage *image, char *kernel,
if (initrd) {
ret = kexec_add_buffer(image, initrd, initrd_len, initrd_len,
PAGE_SIZE, MIN_INITRD_LOAD_ADDR,
- ULONG_MAX, 1, &initrd_load_addr);
+ ULONG_MAX, true, true, &initrd_load_addr);
if (ret)
goto out_free_params;
@@ -98,6 +98,9 @@ struct kexec_segment {
size_t bufsz;
unsigned long mem;
size_t memsz;
+
+ /* Whether this segment is part of the checksum calculation. */
+ bool do_checksum;
};
#ifdef CONFIG_COMPAT
@@ -217,7 +220,7 @@ int kexec_locate_mem_hole(struct kimage *image, unsigned long size,
extern int kexec_add_buffer(struct kimage *image, char *buffer,
unsigned long bufsz, unsigned long memsz,
unsigned long buf_align, unsigned long buf_min,
- unsigned long buf_max, bool top_down,
+ unsigned long buf_max, bool top_down, bool checksum,
unsigned long *load_addr);
extern struct page *kimage_alloc_control_pages(struct kimage *image,
unsigned int order);
@@ -334,7 +337,7 @@ int kexec_add_handover_buffer(struct kimage *image, void *buffer,
unsigned long bufsz, unsigned long memsz,
unsigned long buf_align, unsigned long buf_min,
unsigned long buf_max, bool top_down,
- unsigned long *load_addr);
+ bool checksum, unsigned long *load_addr);
int __weak kexec_get_handover_buffer(void **addr, unsigned long *size);
int __weak kexec_free_handover_buffer(void);
#else
@@ -146,6 +146,7 @@ int __weak arch_kexec_add_handover_buffer(struct kimage *image,
* @buf_min: Minimum address where buffer can be placed.
* @buf_max: Maximum address where buffer can be placed.
* @top_down: Find the highest available memory position for the buffer?
+ * @checksum: Should this buffer checksum be verified by the purgatory?
* @load_addr: On successful return, set to the physical memory address of the
* buffer in the next kernel.
*
@@ -157,7 +158,7 @@ int kexec_add_handover_buffer(struct kimage *image, void *buffer,
unsigned long bufsz, unsigned long memsz,
unsigned long buf_align, unsigned long buf_min,
unsigned long buf_max, bool top_down,
- unsigned long *load_addr)
+ bool checksum, unsigned long *load_addr)
{
int ret;
@@ -165,7 +166,7 @@ int kexec_add_handover_buffer(struct kimage *image, void *buffer,
return -ENOTSUPP;
ret = kexec_add_buffer(image, buffer, bufsz, memsz, buf_align, buf_min,
- buf_max, top_down, load_addr);
+ buf_max, top_down, checksum, load_addr);
if (ret)
return ret;
@@ -590,7 +591,7 @@ int kexec_locate_mem_hole(struct kimage *image, unsigned long size,
int kexec_add_buffer(struct kimage *image, char *buffer, unsigned long bufsz,
unsigned long memsz, unsigned long buf_align,
unsigned long buf_min, unsigned long buf_max,
- bool top_down, unsigned long *load_addr)
+ bool top_down, bool checksum, unsigned long *load_addr)
{
struct kexec_segment *ksegment;
@@ -630,6 +631,7 @@ int kexec_add_buffer(struct kimage *image, char *buffer, unsigned long bufsz,
ksegment->bufsz = bufsz;
ksegment->mem = addr;
ksegment->memsz = size;
+ ksegment->do_checksum = checksum;
image->nr_segments++;
*load_addr = ksegment->mem;
return 0;
@@ -645,7 +647,6 @@ static int kexec_calculate_store_digests(struct kimage *image)
char *digest;
void *zero_buf;
struct kexec_sha_region *sha_regions;
- struct purgatory_info *pi = &image->purgatory_info;
zero_buf = __va(page_to_pfn(ZERO_PAGE(0)) << PAGE_SHIFT);
zero_buf_sz = PAGE_SIZE;
@@ -685,11 +686,7 @@ static int kexec_calculate_store_digests(struct kimage *image)
struct kexec_segment *ksegment;
ksegment = &image->segment[i];
- /*
- * Skip purgatory as it will be modified once we put digest
- * info in purgatory.
- */
- if (ksegment->kbuf == pi->purgatory_buf)
+ if (!ksegment->do_checksum)
continue;
ret = crypto_shash_update(desc, ksegment->kbuf,
@@ -866,9 +863,12 @@ static int __kexec_load_purgatory(struct kimage *image, unsigned long min,
if (buf_align < bss_align)
buf_align = bss_align;
- /* Add buffer to segment list */
+ /*
+ * Add buffer to segment list. Don't checksum the segment as
+ * it will be modified once we put digest info in purgatory.
+ */
ret = kexec_add_buffer(image, purgatory_buf, buf_sz, memsz,
- buf_align, min, max, top_down,
+ buf_align, min, max, top_down, false,
&pi->purgatory_load_addr);
if (ret)
goto out;
Adds checksum argument to kexec_add_buffer specifying whether the given segment should be part of the checksum calculation. The next patch will add a way to update segments after a kimage is loaded. Segments that will be updated in this way should not be checksummed, otherwise they will cause the purgatory checksum verification to fail when the machine is rebooted. As a bonus, we don't need to special-case the purgatory segment anymore to avoid checksumming it. Adjust call sites for the new argument. Signed-off-by: Thiago Jung Bauermann <bauerman@linux.vnet.ibm.com> --- arch/powerpc/kernel/kexec_elf_64.c | 6 +++--- arch/x86/kernel/crash.c | 4 ++-- arch/x86/kernel/kexec-bzimage64.c | 6 +++--- include/linux/kexec.h | 7 +++++-- kernel/kexec_file.c | 22 +++++++++++----------- 5 files changed, 24 insertions(+), 21 deletions(-)