fix(relinker): validate dt_os/dt dynamic tags

This commit is contained in:
boykopovar 2026-08-04 13:35:52 +03:00
parent 39ae562b51
commit be508d9647
2 changed files with 90 additions and 41 deletions

View File

@ -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);
};

View File

@ -49,50 +49,85 @@ RelinkResult RelinkerPipeline::Relink(const std::vector<std::uint8_t>& sourceElf
}
}
FileByteOffset dynStrTabOffset = 0;
FileByteOffset dynSymTabOffset = 0;
FileByteOffset dynRelaOffset = 0;
ByteCount dynRelaSize = 0;
FileByteOffset dynJmpRelOffset = 0;
ByteCount dynJmpRelSize = 0;
std::vector<DynamicTag> dynTags;
bool hasDynamicSegment = false;
std::vector<std::pair<std::uint64_t, std::string>> 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<std::pair<std::uint64_t, std::string>> neededLibraryNamesByStrOffset;
for (const auto& tag : dynTags)
if (tag.Tag == DT_NEEDED)
neededLibraryNamesByStrOffset.emplace_back(tag.Value, std::string());
std::vector<NidReference> nidRefs;
std::vector<std::string> neededLibraries;
@ -145,8 +180,8 @@ RelinkResult RelinkerPipeline::Relink(const std::vector<std::uint8_t>& 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);