:: commit 176c01e7a7bb5207d6826e3240d4cbcd7104c550

Mintsuki <mintsuki@protonmail.com> — 2026-01-13 04:10

parents: ebb67510eb

multiboot2: Add bounds validation for ELF section headers

diff --git a/common/protos/multiboot2.c b/common/protos/multiboot2.c
index 3f113455..c8dedf6d 100644
--- a/common/protos/multiboot2.c
+++ b/common/protos/multiboot2.c
@@ -479,7 +479,13 @@ reloc_fail:
             panic(true, "multiboot2: Cannot return ELF file information");
         }
     } else {
-        uint32_t size = sizeof(struct multiboot_tag_elf_sections) + section_hdr_info.section_entry_size * section_hdr_info.num;
+        size_t section_table_size = (size_t)section_hdr_info.section_entry_size * section_hdr_info.num;
+        if (section_hdr_info.section_offset > kernel_file_size ||
+            section_table_size > kernel_file_size - section_hdr_info.section_offset) {
+            panic(true, "multiboot2: ELF section headers out of bounds");
+        }
+
+        uint32_t size = sizeof(struct multiboot_tag_elf_sections) + section_table_size;
         struct multiboot_tag_elf_sections *tag = (struct multiboot_tag_elf_sections*)(mb2_info + info_idx);
 
         tag->type = MULTIBOOT_TAG_TYPE_ELF_SECTIONS;
@@ -489,7 +495,7 @@ reloc_fail:
         tag->entsize = section_hdr_info.section_entry_size;
         tag->shndx = section_hdr_info.str_section_idx;
 
-        memcpy(tag->sections, kernel + section_hdr_info.section_offset, section_hdr_info.section_entry_size * section_hdr_info.num);
+        memcpy(tag->sections, kernel + section_hdr_info.section_offset, section_table_size);
 
         int bits = elf_bits(kernel);
 
@@ -501,6 +507,11 @@ reloc_fail:
                     continue;
                 }
 
+                if (shdr->sh_offset > kernel_file_size ||
+                    shdr->sh_size > kernel_file_size - shdr->sh_offset) {
+                    continue;
+                }
+
                 uint64_t section = (uint64_t)-1; /* no target preference, use top */
 
                 if (!elsewhere_append(true /* flexible target */,
@@ -517,6 +528,11 @@ reloc_fail:
                     continue;
                 }
 
+                if (shdr->sh_offset > kernel_file_size ||
+                    shdr->sh_size > kernel_file_size - shdr->sh_offset) {
+                    continue;
+                }
+
                 uint64_t section = (uint64_t)-1; /* no target preference, use top */
 
                 if (!elsewhere_append(true /* flexible target */,
tab: 248 wrap: offon