On Wed, Apr 01, 2026, Theo de Raadt wrote: > It feels like even if they are all all unsigned, the largest > unsigned numbers may operate as 32-bit and wrap and therefore be > smaller than s.st_size.
You are right that this is a risk. On 32-bit platforms, Elf32_Off is uint32_t. Without the (off_t) cast, the sum would stay 32-bit and wrap: e_shoff = 4294960000, e_shnum = 200, sizeof(Elf32_Shdr) = 40 uint32: 4294960000 + 8000 = 704 (wrapped) 704 < st_size -> check bypassed The (off_t) cast in the check is specifically there to prevent this. Since off_t is int64_t on OpenBSD (even on 32-bit), the cast forces the multiplication into 64-bit, and the addition then promotes e_shoff to 64-bit as well: h.e_shoff + (off_t)h.e_shnum * sizeof(Elf_Shdr) > s.st_size 1. (off_t)e_shnum: uint16_t -> int64_t 2. int64_t * size_t -> int64_t (product, max ~4MB) 3. uint32_t + int64_t -> int64_t (wider type, no wrap) 4. int64_t > off_t: same type I verified this on OpenBSD 7.8/arm64 with a test program that demonstrates the wrap without the cast and the correct result with it. Check 1 (e_shoff >= st_size) does not catch this case by itself because on 32-bit, e_shoff can be close to UINT32_MAX while still being less than st_size (which is int64_t and can exceed UINT32_MAX for large files).
