If a buildroot enviorment does not provide libzstd and kexec_file_load a
zstd compressed kernel, it will suffer from coredump.

The following is observed from the coredump

Core was generated by `/sbin/kexec -s -p 
--command-line=BOOT_IMAGE=\(hd0,gpt2\)/vmlinuz-6.15.0-0.rc5.250509g9c69f8884904.47.fc43.aarch64\
 ro\ rootflags=subvol=root\ irqpoll\ nr_cpus=1\ reset_devices\ 
cgroup_disable=memory\ udev.children-max=2\ panic=10\ swiotlb=noforce\ 
novmcoredd\ cma=0\ hugetlb_cma=0\ sbsa_gwdt.pretimeout=0 
--initrd=/boot/initramfs-6.15.0-0.rc5.250509g9c69f8884904.47.fc43.aarch64kdump.img
 /boot/vmlinuz-6.15.0-0.rc5.250509g9c69f8884904.47.fc43.aarch64'.
Program terminated with signal SIGSEGV, Segmentation fault.
143             if (!!memcmp(buf, "PE\0\0", 4)) {
(gdb)

Instead of coredump, it is better to exit elegantly by adding checkout
on the PE header offset.

Signed-off-by: Pingfan Liu <pi...@redhat.com>
---
 include/pe.h           | 4 ++++
 kexec/kexec-pe-zboot.c | 5 ++++-
 2 files changed, 8 insertions(+), 1 deletion(-)

diff --git a/include/pe.h b/include/pe.h
index a1aa91e..9ab3e79 100644
--- a/include/pe.h
+++ b/include/pe.h
@@ -139,6 +139,10 @@ static int get_pehdr_offset(const char *buf)
        int pe_hdr_offset;
 
        pe_hdr_offset = *((int *)(buf + 0x3c));
+       if (pe_hdr_offset < 0 || pe_hdr_offset > 4096) {
+               printf("PE header offset is not a reasonable value\n");
+               return -1;
+       }
        buf += pe_hdr_offset;
        if (!!memcmp(buf, "PE\0\0", 4)) {
                printf("Not a PE file\n");
diff --git a/kexec/kexec-pe-zboot.c b/kexec/kexec-pe-zboot.c
index 8e17b4e..c09f2ae 100644
--- a/kexec/kexec-pe-zboot.c
+++ b/kexec/kexec-pe-zboot.c
@@ -100,7 +100,10 @@ int pez_prepare(const char *crude_buf, off_t buf_sz, int 
*kernel_fd,
        dbgprintf("%s: decompressed size %ld\n", __func__, decompressed_size);
 
        /* Makefile.zboot pads Image with zero, but the trailing zero is not 
part of PE file */
-       parse = kernel_uncompressed_buf + 
get_pehdr_offset(kernel_uncompressed_buf);
+       ret = get_pehdr_offset(kernel_uncompressed_buf);
+       if (ret < 0)
+               goto fail_bad_header;
+       parse = kernel_uncompressed_buf + ret;
        parse += sizeof(struct pe_hdr);
        opt_hdr = (struct pe32plus_opt_hdr*)parse;
        parse += sizeof(struct pe32plus_opt_hdr);
-- 
2.49.0


Reply via email to