byte-swap sh_entry_count in elf symtab/dynsym link check (#2214)

Missing byte swap in the ELF symtab/dynsym link check
The SHT_SYMTAB and SHT_DYNSYM string table check compares sh_link against the raw e_shnum (sh_entry_count) while every other use in the macro byte-swaps it, so on a little-endian host reading a big-endian ELF the check accepts a link past the real section count and parses the symbol string table from an out-of-range section header. Swapped it to match the sibling reads, and added a regression test scanning a crafted big-endian ELF whose only symtab carries an out-of-range sh_link.
This commit is contained in:
jmestwa-coder
2026-06-30 20:20:12 +02:00
committed by GitHub
parent 6339e36f5f
commit 622ea976c7
3 changed files with 49 additions and 2 deletions
+4 -2
View File
@@ -559,7 +559,8 @@ static const char* str_table_entry(
} \
\
if (yr_##bo##32toh(section->type) == ELF_SHT_SYMTAB && \
yr_##bo##32toh(section->link) < elf->sh_entry_count) \
yr_##bo##32toh(section->link) < \
yr_##bo##16toh(elf->sh_entry_count)) \
{ \
elf##bits##_section_header_t* string_section = section_table + \
yr_##bo##32toh( \
@@ -577,7 +578,8 @@ static const char* str_table_entry(
} \
\
if (yr_##bo##32toh(section->type) == ELF_SHT_DYNSYM && \
yr_##bo##32toh(section->link) < elf->sh_entry_count) \
yr_##bo##32toh(section->link) < \
yr_##bo##16toh(elf->sh_entry_count)) \
{ \
elf##bits##_section_header_t* dynstr_section = section_table + \
yr_##bo##32toh( \
+33
View File
@@ -2139,6 +2139,39 @@ unsigned char ELF_x64_FILE[] = {
};
// Synthetic big-endian (ELFDATA2MSB) ELF32 used to exercise the symtab/dynsym
// sh_link bounds check. The only SHT_SYMTAB section has sh_link = 4, which is
// >= the real section count (3) but below the un-byteswapped count, so a
// little-endian host that fails to byte-swap e_shnum would treat an
// out-of-range section header as the symbol string table.
unsigned char ELF32_BE_BAD_SYMTAB_LINK[] = {
0x7f, 0x45, 0x4c, 0x46, 0x01, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x03, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x30, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,
0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x00,
0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x42, 0x43, 0x44,
0x00, 0x00, 0x00};
uint8_t MACHO_X86_FILE[] = {
0xce, 0xfa, 0xed, 0xfe, 0x07, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+12
View File
@@ -171,6 +171,18 @@ int main(int argc, char** argv)
}",
ELF32_MIPS_FILE);
// A big-endian symtab whose sh_link is past the real section count must not
// be parsed against an out-of-range section header. Before the e_shnum byte
// swap fix a little-endian host accepted the bogus link and reported a
// phantom symbol named "ABCD".
assert_false_rule_blob(
"import \"elf\" \
rule test { \
condition: \
elf.symtab_entries == 1 and elf.symtab[0].name == \"ABCD\" \
}",
ELF32_BE_BAD_SYMTAB_LINK);
assert_true_rule_blob(
"import \"elf\" \
rule test { \