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) {