From be508d96473d3713a53de1465c87b79731f9655e Mon Sep 17 00:00:00 2001 From: boykopovar Date: Tue, 4 Aug 2026 13:35:52 +0300 Subject: [PATCH] fix(relinker): validate dt_os/dt dynamic tags --- .../relinker/pipeline/RelinkerPipeline.hpp | 28 +++-- .../src/pipeline/RelinkerPipeline.cpp | 103 ++++++++++++------ 2 files changed, 90 insertions(+), 41 deletions(-) diff --git a/core/relinker/include/relinker/pipeline/RelinkerPipeline.hpp b/core/relinker/include/relinker/pipeline/RelinkerPipeline.hpp index e6e9c6861..90fbc5578 100644 --- a/core/relinker/include/relinker/pipeline/RelinkerPipeline.hpp +++ b/core/relinker/include/relinker/pipeline/RelinkerPipeline.hpp @@ -34,17 +34,31 @@ private: static constexpr std::uint32_t PT_DYNAMIC = 2; static constexpr std::uint32_t PF_X = 0x1; - static constexpr std::int64_t DT_PLTGOT = 0x00000003; - static constexpr std::int64_t DT_OS_PLTGOT = 0x61000027; - static constexpr std::int64_t DT_PLTRELSZ = 0x00000002; - static constexpr std::int64_t DT_OS_PLTRELSZ = 0x6100002d; static constexpr std::int64_t DT_NEEDED = 0x00000001; + static constexpr std::int64_t DT_PLTRELSZ = 0x00000002; + static constexpr std::int64_t DT_PLTGOT = 0x00000003; static constexpr std::int64_t DT_STRTAB = 0x00000005; + static constexpr std::int64_t DT_SYMTAB = 0x00000006; static constexpr std::int64_t DT_RELA = 0x00000007; static constexpr std::int64_t DT_RELASZ = 0x00000008; - static constexpr std::int64_t DT_SYSV_JMPREL = 0x00000017; - static constexpr std::int64_t DT_PLTRELSZ_SYSV = 0x00000002; - static constexpr std::int64_t DT_SYMTAB = 0x00000006; + static constexpr std::int64_t DT_RELAENT = 0x00000009; + static constexpr std::int64_t DT_STRSZ = 0x0000000a; + static constexpr std::int64_t DT_SYMENT = 0x0000000b; + static constexpr std::int64_t DT_PLTREL = 0x00000014; + static constexpr std::int64_t DT_JMPREL = 0x00000017; + + static constexpr std::int64_t DT_OS_PLTGOT = 0x61000027; + static constexpr std::int64_t DT_OS_PLTREL = 0x6100002b; + static constexpr std::int64_t DT_OS_PLTRELSZ = 0x6100002d; + static constexpr std::int64_t DT_OS_STRTAB = 0x61000035; + static constexpr std::int64_t DT_OS_STRSZ = 0x61000037; + static constexpr std::int64_t DT_OS_SYMTAB = 0x61000039; + static constexpr std::int64_t DT_OS_SYMENT = 0x6100003b; + static constexpr std::int64_t DT_OS_SYMTABSZ = 0x6100003f; + static constexpr std::int64_t DT_OS_RELA = 0x6100002f; + static constexpr std::int64_t DT_OS_RELASZ = 0x61000031; + static constexpr std::int64_t DT_OS_RELAENT = 0x61000033; + static constexpr std::int64_t DT_OS_JMPREL = 0x61000029; static std::string _relocationTypeName(std::uint32_t type); }; diff --git a/core/relinker/src/pipeline/RelinkerPipeline.cpp b/core/relinker/src/pipeline/RelinkerPipeline.cpp index b212a3c10..716f326b1 100644 --- a/core/relinker/src/pipeline/RelinkerPipeline.cpp +++ b/core/relinker/src/pipeline/RelinkerPipeline.cpp @@ -49,50 +49,85 @@ RelinkResult RelinkerPipeline::Relink(const std::vector& sourceElf } } - FileByteOffset dynStrTabOffset = 0; - FileByteOffset dynSymTabOffset = 0; - FileByteOffset dynRelaOffset = 0; - ByteCount dynRelaSize = 0; - FileByteOffset dynJmpRelOffset = 0; - ByteCount dynJmpRelSize = 0; + std::vector dynTags; bool hasDynamicSegment = false; - std::vector> neededLibraryNamesByStrOffset; for (const auto& ph : programHeaders) { if (ph.Type != PT_DYNAMIC) continue; hasDynamicSegment = true; - - for (const auto& tag : _elfReader->ReadDynamicTags(ph)) { - if (tag.Tag == DT_PLTGOT || tag.Tag == DT_OS_PLTGOT) - gotVAddr = tag.Value; - else if (tag.Tag == DT_PLTRELSZ || tag.Tag == DT_OS_PLTRELSZ) - gotSize = tag.Value; - else if (tag.Tag == DT_STRTAB) - dynStrTabOffset = _elfReader->TranslateVirtualAddress(tag.Value); - else if (tag.Tag == DT_SYMTAB) - dynSymTabOffset = _elfReader->TranslateVirtualAddress(tag.Value); - else if (tag.Tag == DT_RELA) - dynRelaOffset = _elfReader->TranslateVirtualAddress(tag.Value); - else if (tag.Tag == DT_RELASZ) - dynRelaSize = tag.Value; - else if (tag.Tag == DT_SYSV_JMPREL) - dynJmpRelOffset = _elfReader->TranslateVirtualAddress(tag.Value); - else if (tag.Tag == DT_PLTRELSZ_SYSV) - dynJmpRelSize = tag.Value; - else if (tag.Tag == DT_NEEDED) - neededLibraryNamesByStrOffset.emplace_back(tag.Value, std::string()); - } + dynTags = _elfReader->ReadDynamicTags(ph); break; } if (!hasDynamicSegment) throw RelinkerException("No PT_DYNAMIC segment found"); - if (dynStrTabOffset == 0) - throw RelinkerException("DT_STRTAB not found in PT_DYNAMIC segment"); - if (dynSymTabOffset == 0) - throw RelinkerException("DT_SYMTAB not found in PT_DYNAMIC segment"); + + auto hasTag = [&](const std::int64_t tag) { + for (const auto& t : dynTags) + if (t.Tag == tag) + return true; + return false; + }; + + auto getTagValue = [&](const std::int64_t tag) -> std::uint64_t { + for (const auto& t : dynTags) + if (t.Tag == tag) + return t.Value; + throw RelinkerException("DT tag not found"); + }; + + auto requireExactlyOneOf = [&](const std::int64_t osTag, const std::int64_t sysvTag, const char* name) { + const bool hasOs = hasTag(osTag); + const bool hasSysv = hasTag(sysvTag); + if (hasOs && hasSysv) + throw RelinkerException(std::string("Both DT_OS_ and DT_ variants present for ") + name); + if (!hasOs && !hasSysv) + throw RelinkerException(std::string("Neither DT_OS_ nor DT_ variant present for ") + name); + return hasOs; + }; + + auto readAsOffset = [&](const std::int64_t osTag, const std::int64_t sysvTag, const char* name) -> FileByteOffset { + if (requireExactlyOneOf(osTag, sysvTag, name)) + return getTagValue(osTag); + return _elfReader->TranslateVirtualAddress(getTagValue(sysvTag)); + }; + + auto readAsSize = [&](const std::int64_t osTag, const std::int64_t sysvTag, const char* name) -> ByteCount { + requireExactlyOneOf(osTag, sysvTag, name); + return hasTag(osTag) ? getTagValue(osTag) : getTagValue(sysvTag); + }; + + if (requireExactlyOneOf(DT_OS_PLTGOT, DT_PLTGOT, "DT_PLTGOT")) + gotVAddr = getTagValue(DT_OS_PLTGOT); + else + gotVAddr = getTagValue(DT_PLTGOT); + gotSize = readAsSize(DT_OS_PLTRELSZ, DT_PLTRELSZ, "DT_PLTRELSZ"); + + const FileByteOffset dynStrTabOffset = readAsOffset(DT_OS_STRTAB, DT_STRTAB, "DT_STRTAB"); + requireExactlyOneOf(DT_OS_STRSZ, DT_STRSZ, "DT_STRSZ"); + + const FileByteOffset dynSymTabOffset = readAsOffset(DT_OS_SYMTAB, DT_SYMTAB, "DT_SYMTAB"); + requireExactlyOneOf(DT_OS_SYMENT, DT_SYMENT, "DT_SYMENT"); + + const std::int64_t jmprelType = requireExactlyOneOf(DT_OS_PLTREL, DT_PLTREL, "DT_PLTREL") + ? getTagValue(DT_OS_PLTREL) + : getTagValue(DT_PLTREL); + if (jmprelType != DT_RELA) + throw RelinkerException("Unsupported DT_PLTREL type"); + + const FileByteOffset dynJmpRelOffset = readAsOffset(DT_OS_JMPREL, DT_JMPREL, "DT_JMPREL"); + const ByteCount dynJmpRelSize = gotSize; + + const FileByteOffset dynRelaOffset = readAsOffset(DT_OS_RELA, DT_RELA, "DT_RELA"); + const ByteCount dynRelaSize = readAsSize(DT_OS_RELASZ, DT_RELASZ, "DT_RELASZ"); + requireExactlyOneOf(DT_OS_RELAENT, DT_RELAENT, "DT_RELAENT"); + + std::vector> neededLibraryNamesByStrOffset; + for (const auto& tag : dynTags) + if (tag.Tag == DT_NEEDED) + neededLibraryNamesByStrOffset.emplace_back(tag.Value, std::string()); std::vector nidRefs; std::vector neededLibraries; @@ -145,8 +180,8 @@ RelinkResult RelinkerPipeline::Relink(const std::vector& sourceElf } }; - if (dynRelaOffset != 0) extractRela(dynRelaOffset, dynRelaSize); - if (dynJmpRelOffset != 0) extractRela(dynJmpRelOffset, dynJmpRelSize); + extractRela(dynRelaOffset, dynRelaSize); + extractRela(dynJmpRelOffset, dynJmpRelSize); for (const auto& ref : nidRefs) _validationPolicy->ValidateRelocationTypeSupported(ref.RelocationTypeValue, ref.RelocationTableOffset);