From cd0e534db3458f39bc08ca905e24b1967dc0ec4e Mon Sep 17 00:00:00 2001 From: Ethan Barr Date: Tue, 6 Oct 2026 10:42:19 -0700 Subject: [PATCH] fix(relinker): reject malformed dynamic segments --- core/relinker/CMakeLists.txt | 2 + .../relinker/src/parsing/ElfReader.cpp | 13 ++- .../relinker/tests/test_dynamic_segment.py | 81 +++++++++++++++++++ .../relinker/tests/test_elf_offsets.py | 2 +- 4 files changed, 94 insertions(+), 4 deletions(-) create mode 100644 core/relinker/relinker/tests/test_dynamic_segment.py diff --git a/core/relinker/CMakeLists.txt b/core/relinker/CMakeLists.txt index 006738d94..90a1793d3 100644 --- a/core/relinker/CMakeLists.txt +++ b/core/relinker/CMakeLists.txt @@ -192,6 +192,8 @@ if(BUILD_TESTING) if(Python3_Interpreter_FOUND) add_test(NAME elf_offsets COMMAND ${Python3_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/relinker/tests/test_elf_offsets.py $) + add_test(NAME dynamic_segment COMMAND ${Python3_EXECUTABLE} + ${CMAKE_CURRENT_SOURCE_DIR}/relinker/tests/test_dynamic_segment.py $) add_test(NAME optional_plt COMMAND ${Python3_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/relinker/tests/test_optional_plt.py $) add_test(NAME empty_tls COMMAND ${Python3_EXECUTABLE} diff --git a/core/relinker/relinker/src/parsing/ElfReader.cpp b/core/relinker/relinker/src/parsing/ElfReader.cpp index ba8992b17..9b5ff6c1e 100644 --- a/core/relinker/relinker/src/parsing/ElfReader.cpp +++ b/core/relinker/relinker/src/parsing/ElfReader.cpp @@ -170,24 +170,31 @@ std::string ElfReader::_resolveShdrName(std::uint32_t nameOffset, const ElfHeade } std::vector ElfReader::ReadDynamicTags(const ProgramHeader& dynamicHeader) const { + if (!_rangeFits(dynamicHeader.Offset, dynamicHeader.FileSize, _fileBuffer.size())) { + throw RelinkerException("Dynamic segment out of bounds", dynamicHeader.Offset); + } + if (dynamicHeader.FileSize % 16 != 0) { + throw RelinkerException("Invalid dynamic segment size", dynamicHeader.Offset); + } + std::vector tags; FileByteOffset offset = dynamicHeader.Offset; const FileByteOffset end = dynamicHeader.Offset + dynamicHeader.FileSize; - while (offset + 16 <= end && offset + 16 <= _fileBuffer.size()) { + while (offset < end) { DynamicTag tag; tag.Tag = static_cast(_readU64At(offset)); tag.Value = _readU64At(offset + 0x08); if (tag.Tag == 0) { - break; + return tags; } tags.push_back(tag); offset += 16; } - return tags; + throw RelinkerException("Unterminated dynamic segment", dynamicHeader.Offset); } FileByteOffset ElfReader::TranslateVirtualAddress(VirtualAddress address) const { diff --git a/core/relinker/relinker/tests/test_dynamic_segment.py b/core/relinker/relinker/tests/test_dynamic_segment.py new file mode 100644 index 000000000..830b96707 --- /dev/null +++ b/core/relinker/relinker/tests/test_dynamic_segment.py @@ -0,0 +1,81 @@ +from pathlib import Path +import struct +import subprocess +import sys +import tempfile + +from test_optional_plt import fixture as optional_plt_fixture + + +def fixture(): + image = optional_plt_fixture() + struct.pack_into("