mirror of
https://github.com/espressif/esptool.git
synced 2025-10-19 02:43:00 +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):
|
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
|
LEN_SEC_HEADER = 0x28
|
||||||
|
|
||||||
SEG_TYPE_LOAD = 0x01
|
SEG_TYPE_LOAD = 0x01
|
||||||
@@ -1353,6 +1339,22 @@ class ELFFile(object):
|
|||||||
self._read_segments(f, _phoff, _phnum, shstrndx)
|
self._read_segments(f, _phoff, _phnum, shstrndx)
|
||||||
|
|
||||||
def _read_sections(self, f, section_header_offs, section_header_count, 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)
|
f.seek(section_header_offs)
|
||||||
len_bytes = section_header_count * self.LEN_SEC_HEADER
|
len_bytes = section_header_count * self.LEN_SEC_HEADER
|
||||||
section_header = f.read(len_bytes)
|
section_header = f.read(len_bytes)
|
||||||
@@ -1384,17 +1386,13 @@ class ELFFile(object):
|
|||||||
) = struct.unpack_from("<LLLLLLLLL", section_header[offs:])
|
) = struct.unpack_from("<LLLLLLLLL", section_header[offs:])
|
||||||
return (name_offs, sec_type, lma, size, sec_offs, _flags, align)
|
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
|
# search for the string table section
|
||||||
if (shstrndx * self.LEN_SEC_HEADER) not in section_header_offsets:
|
if (shstrndx * self.LEN_SEC_HEADER) not in section_header_offsets:
|
||||||
raise FatalError(f"ELF file has no STRTAB section at shstrndx {shstrndx}")
|
raise FatalError(f"ELF file has no STRTAB section at shstrndx {shstrndx}")
|
||||||
_, sec_type, _, sec_size, sec_offs, _flags, align = read_section_header(
|
_, sec_type, _, sec_size, sec_offs, _flags, align = read_section_header(
|
||||||
shstrndx * self.LEN_SEC_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}")
|
log.warning(f"ELF file has incorrect STRTAB section type {sec_type:#04x}")
|
||||||
f.seek(sec_offs)
|
f.seek(sec_offs)
|
||||||
string_table = f.read(sec_size)
|
string_table = f.read(sec_size)
|
||||||
@@ -1410,23 +1408,42 @@ class ELFFile(object):
|
|||||||
f.seek(offs)
|
f.seek(offs)
|
||||||
return f.read(size)
|
return f.read(size)
|
||||||
|
|
||||||
prog_sections = [
|
all_sections = [read_section_header(offs) for offs in section_header_offsets]
|
||||||
ELFSection(
|
|
||||||
lookup_string(n_offs),
|
self.sections = []
|
||||||
lma,
|
self.nobits_sections = []
|
||||||
read_data(offs, size),
|
# Process all sections and raise an error if an unknown section type is found
|
||||||
flags=_flags,
|
for section in all_sections:
|
||||||
align=align,
|
n_offs, sec_type, lma, size, offs, _flags, align = section
|
||||||
)
|
|
||||||
for (n_offs, _type, lma, size, offs, _flags, align) in prog_sections
|
# Skip sections with lma == 0 or size == 0
|
||||||
if lma != 0 and size > 0
|
if lma == 0 or size == 0:
|
||||||
]
|
continue
|
||||||
self.sections = prog_sections
|
|
||||||
self.nobits_sections = [
|
if sec_type not in KNOWN_SEC_TYPES:
|
||||||
ELFSection(lookup_string(n_offs), lma, b"", flags=_flags, align=align)
|
log.warning(f"Unknown section type {sec_type:#04x} in ELF file")
|
||||||
for (n_offs, _type, lma, size, offs, _flags, align) in nobits_secitons
|
continue
|
||||||
if lma != 0 and size > 0
|
|
||||||
]
|
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):
|
def _read_segments(self, f, segment_header_offs, segment_header_count, shstrndx):
|
||||||
f.seek(segment_header_offs)
|
f.seek(segment_header_offs)
|
||||||
|
@@ -539,6 +539,68 @@ class TestHashAppend(BaseTestCase):
|
|||||||
assert bytes(expected_bin_without_hash) == bin_without_hash
|
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):
|
class TestMMUPageSize(BaseTestCase):
|
||||||
def test_appdesc_aligned(self, capsys):
|
def test_appdesc_aligned(self, capsys):
|
||||||
ELF = "esp32c6-appdesc.elf"
|
ELF = "esp32c6-appdesc.elf"
|
||||||
|
Reference in New Issue
Block a user