The three module converter utilities in common_modules/module_manager/utilities/ declare the ELF header, program header, section header and symbol table entry structures with unsigned long for fields that are 32 bits wide in ELF32. That is only correct where long is 4 bytes, which is Windows with MSVC. On any LP64 host, including the project's default Linux/GCC toolchain, every one of those fields becomes 8 bytes and the structures no longer match the file format.
Evidence
Compiling the structures as declared:
| Build |
ELF_HEADER |
ELF_SECTION_HEADER |
| 64 bit, the Linux/GCC default |
80 |
80 |
| 32 bit, matching MSVC |
52 |
40 |
Real ELF32 (Elf32_Ehdr / Elf32_Shdr) |
52 |
40 |
So a 32 bit build is correct and a 64 bit build is not. The tools read the file with elf_object_read(), which copies raw bytes into these structures, so on a 64 bit host every field after the first two shorts is read from the wrong offset.
Impact
The failure is silent rather than loud. The tools do not validate the ELF magic, so they will read whatever the misaligned offsets happen to contain, and can emit a plausible looking but wrong module binary or C array. Anyone who builds these tools on Linux, which is what AGENTS.md names as the project's default toolchain, gets that behaviour with no warning.
The hardening in #580 does not address this. It makes the tools fail cleanly on a truncated or malformed file, but a correct ELF32 read through mismatched structures is not malformed from the reader's point of view.
Suggested fix
Declare the ELF structures with fixed width types from <stdint.h>: uint32_t for the word fields, uint16_t for the half fields, uint8_t for the identification bytes. That makes the layout correct on any host and removes the dependency on how wide long happens to be.
Worth adding while in there:
- Validate the ELF identification bytes at the start of the file and reject anything that is not an ELF32 little endian object, so a mismatch is reported instead of silently misparsed.
- Add a
_Static_assert on the structure sizes (52 and 40) so this cannot regress unnoticed.
Notes
Found while working on #571 and #580. Not fixed there because it is a different defect from the leak and the malformed input handling, and it changes the parsing itself rather than the error paths.
The three module converter utilities in
common_modules/module_manager/utilities/declare the ELF header, program header, section header and symbol table entry structures withunsigned longfor fields that are 32 bits wide in ELF32. That is only correct wherelongis 4 bytes, which is Windows with MSVC. On any LP64 host, including the project's default Linux/GCC toolchain, every one of those fields becomes 8 bytes and the structures no longer match the file format.Evidence
Compiling the structures as declared:
ELF_HEADERELF_SECTION_HEADERElf32_Ehdr/Elf32_Shdr)So a 32 bit build is correct and a 64 bit build is not. The tools read the file with
elf_object_read(), which copies raw bytes into these structures, so on a 64 bit host every field after the first two shorts is read from the wrong offset.Impact
The failure is silent rather than loud. The tools do not validate the ELF magic, so they will read whatever the misaligned offsets happen to contain, and can emit a plausible looking but wrong module binary or C array. Anyone who builds these tools on Linux, which is what
AGENTS.mdnames as the project's default toolchain, gets that behaviour with no warning.The hardening in #580 does not address this. It makes the tools fail cleanly on a truncated or malformed file, but a correct ELF32 read through mismatched structures is not malformed from the reader's point of view.
Suggested fix
Declare the ELF structures with fixed width types from
<stdint.h>:uint32_tfor the word fields,uint16_tfor the half fields,uint8_tfor the identification bytes. That makes the layout correct on any host and removes the dependency on how widelonghappens to be.Worth adding while in there:
_Static_asserton the structure sizes (52 and 40) so this cannot regress unnoticed.Notes
Found while working on #571 and #580. Not fixed there because it is a different defect from the leak and the malformed input handling, and it changes the parsing itself rather than the error paths.