[PATCH] kexec/zboot: Add boundary check on PE header offset
Pingfan Liu
piliu at redhat.com
Tue May 13 03:32:40 PDT 2025
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 <piliu at 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
More information about the kexec
mailing list