diff --git a/arch/powerpc/kernel/kexec_elf_64.c b/arch/powerpc/kernel/kexec_elf_64.c
index 5d2b7036fee7..abbad484d7b2 100644
--- a/arch/powerpc/kernel/kexec_elf_64.c
+++ b/arch/powerpc/kernel/kexec_elf_64.c
@@ -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;
diff --git a/arch/x86/kernel/crash.c b/arch/x86/kernel/crash.c
index 9ef978d69c22..c8b16f2ca321 100644
--- a/arch/x86/kernel/crash.c
+++ b/arch/x86/kernel/crash.c
@@ -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);diff --git a/arch/x86/kernel/kexec-bzimage64.c b/arch/x86/kernel/kexec-bzimage64.c
index f2356bda2b05..f9016be44da6 100644
--- a/arch/x86/kernel/kexec-bzimage64.c
+++ b/arch/x86/kernel/kexec-bzimage64.c
@@ -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;
diff --git a/include/linux/kexec.h b/include/linux/kexec.h
index 72db95c623b3..131b1fc7820e 100644
--- a/include/linux/kexec.h
+++ b/include/linux/kexec.h
@@ -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
diff --git a/kernel/kexec_file.c b/kernel/kexec_file.c
index d6ba702654f5..3aa829a78f50 100644
--- a/kernel/kexec_file.c
+++ b/kernel/kexec_file.c
@@ -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;
--
1.9.1