Commit 260d49d8e2 for qemu.org
commit 260d49d8e28378b1f4f6c255c15cc20617726920
Author: Alex Bennée <alex.bennee@linaro.org>
Date: Wed Aug 12 09:14:05 2026 +0100
hw/elf_ops: defend against weird elf headers
According to the ELF spec:
PT_LOAD
The array element specifies a loadable segment, described by
p_filesz and p_memsz. The bytes from the file are mapped to the
beginning of the memory segment. If the segment's memory
size (p_memsz) is larger than the file size (p_filesz), the
``extra'' bytes are defined to hold the value 0 and to follow the
segment's initialized area. The file size may not be larger than the
memory size. Loadable segment entries in the program header table
appear in ascending order, sorted on the p_vaddr member.
which implies while both p_filesz and p_memsz can be zero we should
never see a case where p_filesz is greater than the in memory size.
Indeed it has been reported such a hand crafted ELF can blow up, for
example during rom_reset():
address_space_set(rom->as, rom->addr + rom->datasize, 0,
rom->romsize - rom->datasize,
MEMTXATTRS_UNSPECIFIED);
which could trigger and underflow leaving QEMU slowly filling a very
large buffer.
Cc: qemu-stable@nongnu.org
Fixes: https://gitlab.com/qemu-project/qemu/-/work_items/4056
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
Message-ID: <20260812081405.3811787-1-alex.bennee@linaro.org>
Signed-off-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
diff --git a/include/hw/elf_ops.h.inc b/include/hw/elf_ops.h.inc
index 9c35d1b9da..044e72de2a 100644
--- a/include/hw/elf_ops.h.inc
+++ b/include/hw/elf_ops.h.inc
@@ -427,6 +427,11 @@ static ssize_t glue(load_elf, SZ)(const char *name, int fd,
file_size = ph->p_filesz; /* Size of the allocated data */
data_offset = ph->p_offset; /* Offset where the data is located */
+ if (file_size > mem_size) {
+ ret = ELF_LOAD_TOO_BIG;
+ goto fail;
+ }
+
if (file_size > 0) {
if (g_mapped_file_get_length(mapped_file) <
file_size + data_offset) {