Skip to content

Commit 97a1546

Browse files
Dzarda7radimkarnis
authored andcommitted
fix(elf2image): validate ELF section types and addresses before processing
1 parent ec84a75 commit 97a1546

File tree

2 files changed

+115
-36
lines changed

2 files changed

+115
-36
lines changed

esptool/bin_image.py

Lines changed: 53 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1281,20 +1281,6 @@ class ESP32H21FirmwareImage(ESP32C6FirmwareImage):
12811281

12821282

12831283
class ELFFile(object):
1284-
SEC_TYPE_PROGBITS = 0x01
1285-
SEC_TYPE_STRTAB = 0x03
1286-
SEC_TYPE_NOBITS = 0x08 # e.g. .bss section
1287-
SEC_TYPE_INITARRAY = 0x0E
1288-
SEC_TYPE_FINIARRAY = 0x0F
1289-
SEC_TYPE_PREINITARRAY = 0x10
1290-
1291-
PROG_SEC_TYPES = (
1292-
SEC_TYPE_PROGBITS,
1293-
SEC_TYPE_INITARRAY,
1294-
SEC_TYPE_FINIARRAY,
1295-
SEC_TYPE_PREINITARRAY,
1296-
)
1297-
12981284
LEN_SEC_HEADER = 0x28
12991285

13001286
SEG_TYPE_LOAD = 0x01
@@ -1353,6 +1339,22 @@ def _read_elf_file(self, f):
13531339
self._read_segments(f, _phoff, _phnum, shstrndx)
13541340

13551341
def _read_sections(self, f, section_header_offs, section_header_count, shstrndx):
1342+
SEC_TYPE_PROGBITS = 0x01
1343+
SEC_TYPE_STRTAB = 0x03
1344+
SEC_TYPE_NOBITS = 0x08 # e.g. .bss section
1345+
SEC_TYPE_INITARRAY = 0x0E
1346+
SEC_TYPE_FINIARRAY = 0x0F
1347+
SEC_TYPE_PREINITARRAY = 0x10
1348+
1349+
PROG_SEC_TYPES = (
1350+
SEC_TYPE_PROGBITS,
1351+
SEC_TYPE_INITARRAY,
1352+
SEC_TYPE_FINIARRAY,
1353+
SEC_TYPE_PREINITARRAY,
1354+
)
1355+
1356+
KNOWN_SEC_TYPES = PROG_SEC_TYPES + (SEC_TYPE_NOBITS, SEC_TYPE_STRTAB)
1357+
13561358
f.seek(section_header_offs)
13571359
len_bytes = section_header_count * self.LEN_SEC_HEADER
13581360
section_header = f.read(len_bytes)
@@ -1384,17 +1386,13 @@ def read_section_header(offs):
13841386
) = struct.unpack_from("<LLLLLLLLL", section_header[offs:])
13851387
return (name_offs, sec_type, lma, size, sec_offs, _flags, align)
13861388

1387-
all_sections = [read_section_header(offs) for offs in section_header_offsets]
1388-
prog_sections = [s for s in all_sections if s[1] in ELFFile.PROG_SEC_TYPES]
1389-
nobits_secitons = [s for s in all_sections if s[1] == ELFFile.SEC_TYPE_NOBITS]
1390-
13911389
# search for the string table section
13921390
if (shstrndx * self.LEN_SEC_HEADER) not in section_header_offsets:
13931391
raise FatalError(f"ELF file has no STRTAB section at shstrndx {shstrndx}")
13941392
_, sec_type, _, sec_size, sec_offs, _flags, align = read_section_header(
13951393
shstrndx * self.LEN_SEC_HEADER
13961394
)
1397-
if sec_type != ELFFile.SEC_TYPE_STRTAB:
1395+
if sec_type != SEC_TYPE_STRTAB:
13981396
log.warning(f"ELF file has incorrect STRTAB section type {sec_type:#04x}")
13991397
f.seek(sec_offs)
14001398
string_table = f.read(sec_size)
@@ -1410,23 +1408,42 @@ def read_data(offs, size):
14101408
f.seek(offs)
14111409
return f.read(size)
14121410

1413-
prog_sections = [
1414-
ELFSection(
1415-
lookup_string(n_offs),
1416-
lma,
1417-
read_data(offs, size),
1418-
flags=_flags,
1419-
align=align,
1420-
)
1421-
for (n_offs, _type, lma, size, offs, _flags, align) in prog_sections
1422-
if lma != 0 and size > 0
1423-
]
1424-
self.sections = prog_sections
1425-
self.nobits_sections = [
1426-
ELFSection(lookup_string(n_offs), lma, b"", flags=_flags, align=align)
1427-
for (n_offs, _type, lma, size, offs, _flags, align) in nobits_secitons
1428-
if lma != 0 and size > 0
1429-
]
1411+
all_sections = [read_section_header(offs) for offs in section_header_offsets]
1412+
1413+
self.sections = []
1414+
self.nobits_sections = []
1415+
# Process all sections and raise an error if an unknown section type is found
1416+
for section in all_sections:
1417+
n_offs, sec_type, lma, size, offs, _flags, align = section
1418+
1419+
# Skip sections with lma == 0 or size == 0
1420+
if lma == 0 or size == 0:
1421+
continue
1422+
1423+
if sec_type not in KNOWN_SEC_TYPES:
1424+
log.warning(f"Unknown section type {sec_type:#04x} in ELF file")
1425+
continue
1426+
1427+
if sec_type in PROG_SEC_TYPES:
1428+
self.sections.append(
1429+
ELFSection(
1430+
lookup_string(n_offs),
1431+
lma,
1432+
read_data(offs, size),
1433+
flags=_flags,
1434+
align=align,
1435+
)
1436+
)
1437+
elif sec_type == SEC_TYPE_NOBITS:
1438+
self.nobits_sections.append(
1439+
ELFSection(
1440+
lookup_string(n_offs),
1441+
lma,
1442+
b"",
1443+
flags=_flags,
1444+
align=align,
1445+
)
1446+
)
14301447

14311448
def _read_segments(self, f, segment_header_offs, segment_header_count, shstrndx):
14321449
f.seek(segment_header_offs)

test/test_imagegen.py

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -539,6 +539,68 @@ def test_hash_append(self):
539539
assert bytes(expected_bin_without_hash) == bin_without_hash
540540

541541

542+
class TestELFSectionHandling(BaseTestCase):
543+
"""Test ELF section type handling and related functionality."""
544+
545+
@staticmethod
546+
def _modify_section_type(elf_path, section_name, new_type):
547+
"""
548+
Modify the type of a specific section in the ELF file.
549+
"""
550+
with open(elf_path, "rb+") as f:
551+
elf = ELFFile(f)
552+
section = elf.get_section_by_name(section_name)
553+
554+
index = elf.get_section_index(section_name)
555+
# Calculate the section header's position in the file (using section index,
556+
# the section header table's offset and section header entry size)
557+
sh_entry_offset = elf.header["e_shoff"] + index * elf.header["e_shentsize"]
558+
559+
# Modify the section type in the header
560+
section.header.sh_type = new_type
561+
562+
f.seek(sh_entry_offset)
563+
f.write(elf.structs.Elf_Shdr.build(section.header))
564+
565+
@staticmethod
566+
def _get_section_type(elf_path, section_name):
567+
"""
568+
Get the current type of a specific section in the ELF file.
569+
"""
570+
with open(elf_path, "rb") as f:
571+
elf = ELFFile(f)
572+
section = elf.get_section_by_name(section_name)
573+
return section.header.sh_type
574+
575+
def test_unknown_section_type_warning(self, capsys):
576+
"""Test that unknown section types generate the expected warning message."""
577+
ELF = "esp32c6-appdesc.elf"
578+
BIN = "esp32c6-appdesc.bin"
579+
SECTION_NAME = ".flash.appdesc"
580+
UNKNOWN_TYPE = 0x99
581+
582+
original_sec_type = self._get_section_type(ELF, SECTION_NAME)
583+
584+
# Modify the section to have an unknown type
585+
self._modify_section_type(ELF, SECTION_NAME, UNKNOWN_TYPE)
586+
587+
# Verify the section was actually modified
588+
modified_type = self._get_section_type(ELF, SECTION_NAME)
589+
assert modified_type == UNKNOWN_TYPE
590+
591+
try:
592+
self.run_elf2image("esp32c6", ELF, allow_warnings=True)
593+
output = capsys.readouterr().out
594+
print(output)
595+
596+
expected_warning = f"Unknown section type {UNKNOWN_TYPE:#04x} in ELF file"
597+
assert expected_warning in output
598+
599+
finally:
600+
self._modify_section_type(ELF, SECTION_NAME, original_sec_type)
601+
try_delete(BIN)
602+
603+
542604
class TestMMUPageSize(BaseTestCase):
543605
def test_appdesc_aligned(self, capsys):
544606
ELF = "esp32c6-appdesc.elf"

0 commit comments

Comments
 (0)