:: commit cc586e6cc03d211f70b462905b443f64c039d5e2

Mintsuki <mintsuki@protonmail.com> — 2026-03-31 12:42

parents: 3a73ecf5bd

misc: Use CHECKED_ADD for overflow-checked additions

diff --git a/common/fs/fat32.s2.c b/common/fs/fat32.s2.c
index cfac7417..dc287868 100644
--- a/common/fs/fat32.s2.c
+++ b/common/fs/fat32.s2.c
@@ -213,10 +213,7 @@ bytes_per_sector_valid:;
     switch (context->type) {
         case 12:
         case 16:
-            // Check for overflow in data_start_lba calculation
-            if (__builtin_add_overflow(context->root_start, context->root_size, &context->data_start_lba)) {
-                return 1;
-            }
+            context->data_start_lba = CHECKED_ADD(context->root_start, context->root_size, return 1);
             break;
         case 32:
             context->data_start_lba = context->root_start;
@@ -642,9 +639,7 @@ struct file_handle *fat32_open(struct volume *part, const char *path) {
         for (unsigned int i = 0; i < SIZEOF_ARRAY(current_part) - 1; i++) {
             // Check for overflow before computing path index
             unsigned int path_idx;
-            if (__builtin_add_overflow(i, current_index, &path_idx)) {
-                return NULL;  // Path index would overflow
-            }
+            path_idx = CHECKED_ADD(i, current_index, return NULL);
 
             if (path[path_idx] == 0) {
                 memcpy(current_part, path + current_index, i);
@@ -657,12 +652,7 @@ struct file_handle *fat32_open(struct volume *part, const char *path) {
             if (path[path_idx] == '/') {
                 memcpy(current_part, path + current_index, i);
                 current_part[i] = 0;
-                // Check for overflow before updating current_index
-                unsigned int new_index;
-                if (__builtin_add_overflow(current_index, i + 1, &new_index)) {
-                    return NULL;  // current_index would overflow
-                }
-                current_index = new_index;
+                current_index = CHECKED_ADD(current_index, i + 1, return NULL);
                 expect_directory = true;
                 found_terminator = true;
                 break;
diff --git a/common/lib/acpi.c b/common/lib/acpi.c
index 32e9c655..b012dd1c 100644
--- a/common/lib/acpi.c
+++ b/common/lib/acpi.c
@@ -260,11 +260,11 @@ static bool acpi_padding_is_safe(uint64_t base, uint64_t length) {
         return true;
     }
 
-    uint64_t top = base + length;
+    uint64_t top = CHECKED_ADD(base, length, return false);
 
     for (size_t i = 0; i < memmap_entries; i++) {
         uint64_t entry_base = memmap[i].base;
-        uint64_t entry_top  = entry_base + memmap[i].length;
+        uint64_t entry_top  = CHECKED_ADD(entry_base, memmap[i].length, continue);
 
         if (entry_base >= top || entry_top <= base) {
             continue;
diff --git a/common/lib/elf.c b/common/lib/elf.c
index ee686bd3..cfe5b6f6 100644
--- a/common/lib/elf.c
+++ b/common/lib/elf.c
@@ -887,10 +887,8 @@ bool elf64_load(uint8_t *elf, size_t file_size, uint64_t *entry_point, uint64_t
             }
         }
 
-        uint64_t phdr_end;
-        if (__builtin_add_overflow(phdr->p_vaddr, phdr->p_memsz, &phdr_end)) {
-            panic(true, "elf: p_vaddr + p_memsz overflow in PHDR %u", i);
-        }
+        uint64_t phdr_end = CHECKED_ADD(phdr->p_vaddr, phdr->p_memsz,
+            panic(true, "elf: p_vaddr + p_memsz overflow in PHDR %u", i));
 
         // check for overlapping phdrs
         for (uint16_t j = 0; j < hdr->ph_num; j++) {
@@ -910,10 +908,8 @@ bool elf64_load(uint8_t *elf, size_t file_size, uint64_t *entry_point, uint64_t
                 continue;
             }
 
-            uint64_t phdr_in_end;
-            if (__builtin_add_overflow(phdr_in->p_vaddr, phdr_in->p_memsz, &phdr_in_end)) {
-                panic(true, "elf: p_vaddr + p_memsz overflow in PHDR %u", j);
-            }
+            uint64_t phdr_in_end = CHECKED_ADD(phdr_in->p_vaddr, phdr_in->p_memsz,
+                panic(true, "elf: p_vaddr + p_memsz overflow in PHDR %u", j));
 
             if ((phdr_in->p_vaddr >= phdr->p_vaddr
               && phdr_in->p_vaddr < phdr_end)
@@ -994,10 +990,8 @@ again:
         }
 
         // Validate p_offset + p_filesz doesn't overflow or exceed file size
-        uint64_t offset_end;
-        if (__builtin_add_overflow(phdr->p_offset, phdr->p_filesz, &offset_end)) {
-            panic(true, "elf: p_offset + p_filesz overflow");
-        }
+        uint64_t offset_end = CHECKED_ADD(phdr->p_offset, phdr->p_filesz,
+            panic(true, "elf: p_offset + p_filesz overflow"));
         if (offset_end > file_size) {
             panic(true, "elf: p_offset + p_filesz exceeds file size");
         }
@@ -1005,7 +999,8 @@ again:
         uint64_t load_addr = *physical_base + (phdr->p_vaddr - *virtual_base);
 
 #if defined (__aarch64__)
-        uint64_t this_top = load_addr + phdr->p_memsz;
+        uint64_t this_top = CHECKED_ADD(load_addr, phdr->p_memsz,
+            panic(true, "elf: load_addr + p_memsz overflow"));
 
         uint64_t mem_base, mem_size;
 
@@ -1082,7 +1077,8 @@ bool elf32_load_elsewhere(uint8_t *elf, size_t file_size, uint64_t *entry_point,
             min_paddr = phdr->p_paddr;
         }
 
-        uint64_t top = (uint64_t)phdr->p_paddr + phdr->p_memsz;
+        uint64_t top = CHECKED_ADD((uint64_t)phdr->p_paddr, phdr->p_memsz,
+            panic(true, "elf: p_paddr + p_memsz overflow"));
         if (top > max_paddr) {
             max_paddr = top;
         }
@@ -1107,7 +1103,9 @@ bool elf32_load_elsewhere(uint8_t *elf, size_t file_size, uint64_t *entry_point,
         if (phdr->p_filesz > phdr->p_memsz) {
             panic(true, "elf: p_filesz > p_memsz");
         }
-        if ((uint64_t)phdr->p_offset + phdr->p_filesz > file_size) {
+        uint64_t offset_end = CHECKED_ADD((uint64_t)phdr->p_offset, phdr->p_filesz,
+            panic(true, "elf: p_offset + p_filesz overflow"));
+        if (offset_end > file_size) {
             panic(true, "elf: p_offset + p_filesz exceeds file size");
         }
 
@@ -1115,7 +1113,7 @@ bool elf32_load_elsewhere(uint8_t *elf, size_t file_size, uint64_t *entry_point,
 
         if (!entry_adjusted
          && *entry_point >= phdr->p_vaddr
-         && *entry_point < (phdr->p_vaddr + phdr->p_memsz)) {
+         && *entry_point < CHECKED_ADD(phdr->p_vaddr, phdr->p_memsz, continue)) {
             *entry_point -= phdr->p_vaddr;
             *entry_point += phdr->p_paddr;
             entry_adjusted = true;
@@ -1160,10 +1158,8 @@ bool elf64_load_elsewhere(uint8_t *elf, size_t file_size, uint64_t *entry_point,
             min_paddr = phdr->p_paddr;
         }
 
-        uint64_t top;
-        if (__builtin_add_overflow(phdr->p_paddr, phdr->p_memsz, &top)) {
-            panic(true, "elf: p_paddr + p_memsz overflow");
-        }
+        uint64_t top = CHECKED_ADD(phdr->p_paddr, phdr->p_memsz,
+            panic(true, "elf: p_paddr + p_memsz overflow"));
         if (top > max_paddr) {
             max_paddr = top;
         }
@@ -1188,9 +1184,9 @@ bool elf64_load_elsewhere(uint8_t *elf, size_t file_size, uint64_t *entry_point,
         if (phdr->p_filesz > phdr->p_memsz) {
             panic(true, "elf: p_filesz > p_memsz");
         }
-        uint64_t offset_end;
-        if (__builtin_add_overflow(phdr->p_offset, phdr->p_filesz, &offset_end)
-            || offset_end > file_size) {
+        uint64_t offset_end = CHECKED_ADD(phdr->p_offset, phdr->p_filesz,
+            panic(true, "elf: p_offset + p_filesz overflow"));
+        if (offset_end > file_size) {
             panic(true, "elf: p_offset + p_filesz exceeds file size");
         }
 
@@ -1198,7 +1194,7 @@ bool elf64_load_elsewhere(uint8_t *elf, size_t file_size, uint64_t *entry_point,
 
         if (!entry_adjusted
          && *entry_point >= phdr->p_vaddr
-         && *entry_point < (phdr->p_vaddr + phdr->p_memsz)) {
+         && *entry_point < CHECKED_ADD(phdr->p_vaddr, phdr->p_memsz, continue)) {
             *entry_point -= phdr->p_vaddr;
             *entry_point += phdr->p_paddr;
             entry_adjusted = true;
diff --git a/common/lib/misc.s2.c b/common/lib/misc.s2.c
index 78cdb881..5dbb29fe 100644
--- a/common/lib/misc.s2.c
+++ b/common/lib/misc.s2.c
@@ -44,11 +44,11 @@ uint64_t strtoui(const char *s, const char **end, int base) {
                 *end = &s[i];
             return UINT64_MAX;
         }
-        if (__builtin_add_overflow(mul_result, (uint64_t)d, &n)) {
+        n = CHECKED_ADD(mul_result, (uint64_t)d, ({
             if (end != NULL)
                 *end = &s[i];
             return UINT64_MAX;
-        }
+        }));
     }
     return n;
 }
diff --git a/common/lib/part.s2.c b/common/lib/part.s2.c
index 422ec89b..8d61c932 100644
--- a/common/lib/part.s2.c
+++ b/common/lib/part.s2.c
@@ -39,10 +39,7 @@ static bool cache_block(struct volume *volume, uint64_t block) {
     if (__builtin_mul_overflow(block, volume->fastest_xfer_size, &block_offset)) {
         return false;
     }
-    uint64_t read_sector;
-    if (__builtin_add_overflow(first_sect, block_offset, &read_sector)) {
-        return false;
-    }
+    uint64_t read_sector = CHECKED_ADD(first_sect, block_offset, return false);
 
     // Clamp xfer_size to remaining sectors in volume
     if (volume->sect_count != (uint64_t)-1) {
@@ -227,9 +224,7 @@ static int gpt_get_part(struct volume *ret, struct volume *volume, int partition
     }
     // Use actual entry size from header for offset calculation
     uint64_t partition_offset = (uint64_t)partition * entry_size;
-    if (__builtin_add_overflow(entry_offset, partition_offset, &entry_offset)) {
-        return INVALID_TABLE;  // Addition overflow would occur
-    }
+    entry_offset = CHECKED_ADD(entry_offset, partition_offset, return INVALID_TABLE);
 
     struct gpt_entry entry = {0};
     if (!volume_read(volume, &entry, entry_offset, sizeof(entry))) {
@@ -428,17 +423,9 @@ static int mbr_get_logical_part(struct volume *ret, struct volume *extended_part
     }
 
     // Check for overflow in first_sect calculation
-    uint64_t first_sect_64;
-    if (__builtin_add_overflow(extended_part->first_sect, ebr_sector, &first_sect_64)) {
-        return NO_PARTITION;  // Addition overflow
-    }
-    if (__builtin_add_overflow(first_sect_64, (uint64_t)entry.first_sect, &first_sect_64)) {
-        return NO_PARTITION;  // Addition overflow
-    }
-    uint64_t partition_end;
-    if (__builtin_add_overflow(first_sect_64, (uint64_t)entry.sect_count, &partition_end)) {
-        return NO_PARTITION;  // Partition would overflow
-    }
+    uint64_t first_sect_64 = CHECKED_ADD(extended_part->first_sect, ebr_sector, return NO_PARTITION);
+    first_sect_64 = CHECKED_ADD(first_sect_64, (uint64_t)entry.first_sect, return NO_PARTITION);
+    (void)CHECKED_ADD(first_sect_64, (uint64_t)entry.sect_count, return NO_PARTITION);
 
 #if defined (UEFI)
     ret->efi_handle  = extended_part->efi_handle;
diff --git a/common/protos/limine.c b/common/protos/limine.c
index f2fe591d..475ce4e5 100644
--- a/common/protos/limine.c
+++ b/common/protos/limine.c
@@ -79,7 +79,7 @@ static uint64_t get_hhdm_span_top(int base_revision) {
 
         uint64_t base = memmap[i].base;
         uint64_t length = memmap[i].length;
-        uint64_t top = base + length;
+        uint64_t top = CHECKED_ADD(base, length, continue);
 
         if (base_revision < 3 && base < 0x100000000) {
             base = 0x100000000;
@@ -123,7 +123,7 @@ static pagemap_t build_identity_map(void) {
 
         uint64_t base   = _memmap[i].base;
         uint64_t length = _memmap[i].length;
-        uint64_t top    = base + length;
+        uint64_t top    = CHECKED_ADD(base, length, continue);
 
         if (base < 0x100000000) {
             base = 0x100000000;
@@ -226,7 +226,7 @@ static pagemap_t build_pagemap(int base_revision,
 
         uint64_t base   = _memmap[i].base;
         uint64_t length = _memmap[i].length;
-        uint64_t top    = base + length;
+        uint64_t top    = CHECKED_ADD(base, length, goto flush);
 
         if (base_revision < 3 && base < 0x100000000) {
             base = 0x100000000;
@@ -272,7 +272,7 @@ flush:
 
         uint64_t base   = _memmap[i].base;
         uint64_t length = _memmap[i].length;
-        uint64_t top    = base + length;
+        uint64_t top    = CHECKED_ADD(base, length, continue);
 
         uint64_t aligned_base   = ALIGN_DOWN(base, 0x1000);
         uint64_t aligned_top    = ALIGN_UP(top, 0x1000);
@@ -1344,7 +1344,7 @@ FEAT_END
         }
 
         uint64_t fb_base = memmap[i].base;
-        uint64_t fb_top = fb_base + memmap[i].length;
+        uint64_t fb_top = CHECKED_ADD(fb_base, memmap[i].length, continue);
         uint64_t fb_aligned_base = ALIGN_DOWN(fb_base, 4096);
         uint64_t fb_aligned_top = ALIGN_UP(fb_top, 4096);
 
@@ -1359,7 +1359,7 @@ FEAT_END
             }
 
             uint64_t region_base = memmap[j].base;
-            uint64_t region_top = region_base + memmap[j].length;
+            uint64_t region_top = CHECKED_ADD(region_base, memmap[j].length, continue);
 
             // Check if this region overlaps with the framebuffer's page-aligned extent.
             if (region_top <= fb_aligned_base || region_base >= fb_aligned_top) {
diff --git a/common/protos/linux_x86.c b/common/protos/linux_x86.c
index cce595ec..e99d46dc 100644
--- a/common/protos/linux_x86.c
+++ b/common/protos/linux_x86.c
@@ -442,9 +442,8 @@ noreturn void linux_load(char *config, char *cmdline) {
         if ((module = uri_open(module_path)) == NULL)
             panic(true, "linux: Failed to open module with path `%s`. Is the path correct?", module_path);
 
-        if (__builtin_add_overflow(size_of_all_modules, module->size, &size_of_all_modules)) {
-            panic(true, "linux: Total module size overflow");
-        }
+        size_of_all_modules = CHECKED_ADD(size_of_all_modules, module->size,
+            panic(true, "linux: Total module size overflow"));
 
         modules[i] = module;
     }
diff --git a/common/protos/multiboot2.c b/common/protos/multiboot2.c
index 18721cd3..d3fdf6e6 100644
--- a/common/protos/multiboot2.c
+++ b/common/protos/multiboot2.c
@@ -382,7 +382,7 @@ noreturn void multiboot2_load(char *config, char* cmdline) {
             case 0: case 1: // No preference / prefer lowest
                 reloc_ascend = true;
                 relocated_base = ALIGN_UP(reloc_tag.min_addr, reloc_tag.align);
-                if (relocated_base + ranges->length > reloc_tag.max_addr) {
+                if (CHECKED_ADD(relocated_base, ranges->length, goto reloc_fail) > reloc_tag.max_addr) {
                     goto reloc_fail;
                 }
                 break;
@@ -399,13 +399,13 @@ noreturn void multiboot2_load(char *config, char* cmdline) {
         }
 
         for (;;) {
-            if (check_usable_memory(relocated_base, relocated_base + ranges->length)) {
+            if (check_usable_memory(relocated_base, CHECKED_ADD(relocated_base, ranges->length, goto reloc_fail))) {
                 break;
             }
 
             if (reloc_ascend) {
                 relocated_base += reloc_tag.align;
-                if (relocated_base + ranges->length > reloc_tag.max_addr) {
+                if (CHECKED_ADD(relocated_base, ranges->length, goto reloc_fail) > reloc_tag.max_addr) {
                     goto reloc_fail;
                 }
             } else {
tab: 248 wrap: offon