mirror of
https://github.com/espressif/esptool.git
synced 2025-10-15 21:07:25 +08:00
fix(elf2image): validate ELF section types and addresses before processing
This commit is contained in:

committed by
Radim Karniš

parent
ec84a75777
commit
97a1546166
@@ -1281,20 +1281,6 @@ ESP32H21ROM.BOOTLOADER_IMAGE = ESP32H21FirmwareImage
|
||||
|
||||
|
||||
class ELFFile(object):
|
||||
SEC_TYPE_PROGBITS = 0x01
|
||||
SEC_TYPE_STRTAB = 0x03
|
||||
SEC_TYPE_NOBITS = 0x08 # e.g. .bss section
|
||||
SEC_TYPE_INITARRAY = 0x0E
|
||||
SEC_TYPE_FINIARRAY = 0x0F
|
||||
SEC_TYPE_PREINITARRAY = 0x10
|
||||
|
||||
PROG_SEC_TYPES = (
|
||||
SEC_TYPE_PROGBITS,
|
||||
SEC_TYPE_INITARRAY,
|
||||
SEC_TYPE_FINIARRAY,
|
||||
SEC_TYPE_PREINITARRAY,
|
||||
)
|
||||
|
||||
LEN_SEC_HEADER = 0x28
|
||||
|
||||
SEG_TYPE_LOAD = 0x01
|
||||
@@ -1353,6 +1339,22 @@ class ELFFile(object):
|
||||
self._read_segments(f, _phoff, _phnum, shstrndx)
|
||||
|
||||
def _read_sections(self, f, section_header_offs, section_header_count, shstrndx):
|
||||
SEC_TYPE_PROGBITS = 0x01
|
||||
SEC_TYPE_STRTAB = 0x03
|
||||
SEC_TYPE_NOBITS = 0x08 # e.g. .bss section
|
||||
SEC_TYPE_INITARRAY = 0x0E
|
||||
SEC_TYPE_FINIARRAY = 0x0F
|
||||
SEC_TYPE_PREINITARRAY = 0x10
|
||||
|
||||
PROG_SEC_TYPES = (
|
||||
SEC_TYPE_PROGBITS,
|
||||
SEC_TYPE_INITARRAY,
|
||||
SEC_TYPE_FINIARRAY,
|
||||
SEC_TYPE_PREINITARRAY,
|
||||
)
|
||||
|
||||
KNOWN_SEC_TYPES = PROG_SEC_TYPES + (SEC_TYPE_NOBITS, SEC_TYPE_STRTAB)
|
||||
|
||||
f.seek(section_header_offs)
|
||||
len_bytes = section_header_count * self.LEN_SEC_HEADER
|
||||
section_header = f.read(len_bytes)
|
||||
@@ -1384,17 +1386,13 @@ class ELFFile(object):
|
||||
) = struct.unpack_from("<LLLLLLLLL", section_header[offs:])
|
||||
return (name_offs, sec_type, lma, size, sec_offs, _flags, align)
|
||||
|
||||
all_sections = [read_section_header(offs) for offs in section_header_offsets]
|
||||
prog_sections = [s for s in all_sections if s[1] in ELFFile.PROG_SEC_TYPES]
|
||||
nobits_secitons = [s for s in all_sections if s[1] == ELFFile.SEC_TYPE_NOBITS]
|
||||
|
||||
# search for the string table section
|
||||
if (shstrndx * self.LEN_SEC_HEADER) not in section_header_offsets:
|
||||
raise FatalError(f"ELF file has no STRTAB section at shstrndx {shstrndx}")
|
||||
_, sec_type, _, sec_size, sec_offs, _flags, align = read_section_header(
|
||||
shstrndx * self.LEN_SEC_HEADER
|
||||
)
|
||||
if sec_type != ELFFile.SEC_TYPE_STRTAB:
|
||||
if sec_type != SEC_TYPE_STRTAB:
|
||||
log.warning(f"ELF file has incorrect STRTAB section type {sec_type:#04x}")
|
||||
f.seek(sec_offs)
|
||||
string_table = f.read(sec_size)
|
||||
@@ -1410,23 +1408,42 @@ class ELFFile(object):
|
||||
f.seek(offs)
|
||||
return f.read(size)
|
||||
|
||||
prog_sections = [
|
||||
ELFSection(
|
||||
lookup_string(n_offs),
|
||||
lma,
|
||||
read_data(offs, size),
|
||||
flags=_flags,
|
||||
align=align,
|
||||
)
|
||||
for (n_offs, _type, lma, size, offs, _flags, align) in prog_sections
|
||||
if lma != 0 and size > 0
|
||||
]
|
||||
self.sections = prog_sections
|
||||
self.nobits_sections = [
|
||||
ELFSection(lookup_string(n_offs), lma, b"", flags=_flags, align=align)
|
||||
for (n_offs, _type, lma, size, offs, _flags, align) in nobits_secitons
|
||||
if lma != 0 and size > 0
|
||||
]
|
||||
all_sections = [read_section_header(offs) for offs in section_header_offsets]
|
||||
|
||||
self.sections = []
|
||||
self.nobits_sections = []
|
||||
# Process all sections and raise an error if an unknown section type is found
|
||||
for section in all_sections:
|
||||
n_offs, sec_type, lma, size, offs, _flags, align = section
|
||||
|
||||
# Skip sections with lma == 0 or size == 0
|
||||
if lma == 0 or size == 0:
|
||||
continue
|
||||
|
||||
if sec_type not in KNOWN_SEC_TYPES:
|
||||
log.warning(f"Unknown section type {sec_type:#04x} in ELF file")
|
||||
continue
|
||||
|
||||
if sec_type in PROG_SEC_TYPES:
|
||||
self.sections.append(
|
||||
ELFSection(
|
||||
lookup_string(n_offs),
|
||||
lma,
|
||||
read_data(offs, size),
|
||||
flags=_flags,
|
||||
align=align,
|
||||
)
|
||||
)
|
||||
elif sec_type == SEC_TYPE_NOBITS:
|
||||
self.nobits_sections.append(
|
||||
ELFSection(
|
||||
lookup_string(n_offs),
|
||||
lma,
|
||||
b"",
|
||||
flags=_flags,
|
||||
align=align,
|
||||
)
|
||||
)
|
||||
|
||||
def _read_segments(self, f, segment_header_offs, segment_header_count, shstrndx):
|
||||
f.seek(segment_header_offs)
|
||||
|
@@ -539,6 +539,68 @@ class TestHashAppend(BaseTestCase):
|
||||
assert bytes(expected_bin_without_hash) == bin_without_hash
|
||||
|
||||
|
||||
class TestELFSectionHandling(BaseTestCase):
|
||||
"""Test ELF section type handling and related functionality."""
|
||||
|
||||
@staticmethod
|
||||
def _modify_section_type(elf_path, section_name, new_type):
|
||||
"""
|
||||
Modify the type of a specific section in the ELF file.
|
||||
"""
|
||||
with open(elf_path, "rb+") as f:
|
||||
elf = ELFFile(f)
|
||||
section = elf.get_section_by_name(section_name)
|
||||
|
||||
index = elf.get_section_index(section_name)
|
||||
# Calculate the section header's position in the file (using section index,
|
||||
# the section header table's offset and section header entry size)
|
||||
sh_entry_offset = elf.header["e_shoff"] + index * elf.header["e_shentsize"]
|
||||
|
||||
# Modify the section type in the header
|
||||
section.header.sh_type = new_type
|
||||
|
||||
f.seek(sh_entry_offset)
|
||||
f.write(elf.structs.Elf_Shdr.build(section.header))
|
||||
|
||||
@staticmethod
|
||||
def _get_section_type(elf_path, section_name):
|
||||
"""
|
||||
Get the current type of a specific section in the ELF file.
|
||||
"""
|
||||
with open(elf_path, "rb") as f:
|
||||
elf = ELFFile(f)
|
||||
section = elf.get_section_by_name(section_name)
|
||||
return section.header.sh_type
|
||||
|
||||
def test_unknown_section_type_warning(self, capsys):
|
||||
"""Test that unknown section types generate the expected warning message."""
|
||||
ELF = "esp32c6-appdesc.elf"
|
||||
BIN = "esp32c6-appdesc.bin"
|
||||
SECTION_NAME = ".flash.appdesc"
|
||||
UNKNOWN_TYPE = 0x99
|
||||
|
||||
original_sec_type = self._get_section_type(ELF, SECTION_NAME)
|
||||
|
||||
# Modify the section to have an unknown type
|
||||
self._modify_section_type(ELF, SECTION_NAME, UNKNOWN_TYPE)
|
||||
|
||||
# Verify the section was actually modified
|
||||
modified_type = self._get_section_type(ELF, SECTION_NAME)
|
||||
assert modified_type == UNKNOWN_TYPE
|
||||
|
||||
try:
|
||||
self.run_elf2image("esp32c6", ELF, allow_warnings=True)
|
||||
output = capsys.readouterr().out
|
||||
print(output)
|
||||
|
||||
expected_warning = f"Unknown section type {UNKNOWN_TYPE:#04x} in ELF file"
|
||||
assert expected_warning in output
|
||||
|
||||
finally:
|
||||
self._modify_section_type(ELF, SECTION_NAME, original_sec_type)
|
||||
try_delete(BIN)
|
||||
|
||||
|
||||
class TestMMUPageSize(BaseTestCase):
|
||||
def test_appdesc_aligned(self, capsys):
|
||||
ELF = "esp32c6-appdesc.elf"
|
||||
|
Reference in New Issue
Block a user