[Orc] Always check mapped sections for ELFDebugObject are in bounds of working memory buffer

As stated in the JITLink user guide: Do not assume that the input object is well formed.
https://llvm.org/docs/JITLink.html#tips-for-jitlink-backend-developers
This commit is contained in:
Stefan Gränitz 2021-03-09 12:51:51 +01:00
parent 6a3a386c6f
commit 265bc5af7b
2 changed files with 40 additions and 12 deletions

View File

@ -20,7 +20,7 @@
#include "llvm/ExecutionEngine/Orc/TPCDebugObjectRegistrar.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/Memory.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/MemoryBufferRef.h"
#include <functional>
#include <map>

View File

@ -50,6 +50,8 @@ public:
void setTargetMemoryRange(SectionRange Range) override;
void dump(raw_ostream &OS, StringRef Name) override;
Error validateInBounds(StringRef Buffer, const char *Name) const;
private:
typename ELFT::Shdr *Header;
@ -64,15 +66,6 @@ void ELFDebugObjectSection<ELFT>::setTargetMemoryRange(SectionRange Range) {
}
}
template <typename ELFT>
void ELFDebugObjectSection<ELFT>::dump(raw_ostream &OS, StringRef Name) {
if (auto Addr = static_cast<JITTargetAddress>(Header->sh_addr)) {
OS << formatv(" {0:x16} {1}\n", Addr, Name);
} else {
OS << formatv(" {0}\n", Name);
}
}
template <typename ELFT>
bool ELFDebugObjectSection<ELFT>::isTextOrDataSection() const {
switch (Header->sh_type) {
@ -83,6 +76,37 @@ bool ELFDebugObjectSection<ELFT>::isTextOrDataSection() const {
return false;
}
template <typename ELFT>
Error ELFDebugObjectSection<ELFT>::validateInBounds(StringRef Buffer,
const char *Name) const {
const uint8_t *Start = Buffer.bytes_begin();
const uint8_t *End = Buffer.bytes_end();
const uint8_t *HeaderPtr = reinterpret_cast<uint8_t *>(Header);
if (HeaderPtr < Start || HeaderPtr + sizeof(typename ELFT::Shdr) > End)
return make_error<StringError>(
formatv("{0} section header at {1:x16} not within bounds of the "
"given debug object buffer [{2:x16} - {3:x16}]",
Name, &Header->sh_addr, Start, End),
inconvertibleErrorCode());
if (Header->sh_offset + Header->sh_size > Buffer.size())
return make_error<StringError>(
formatv("{0} section data [{1:x16} - {2:x16}] not within bounds of "
"the given debug object buffer [{3:x16} - {4:x16}]",
Name, Start + Header->sh_offset,
Start + Header->sh_offset + Header->sh_size, Start, End),
inconvertibleErrorCode());
return Error::success();
}
template <typename ELFT>
void ELFDebugObjectSection<ELFT>::dump(raw_ostream &OS, StringRef Name) {
if (auto Addr = static_cast<JITTargetAddress>(Header->sh_addr)) {
OS << formatv(" {0:x16} {1}\n", Addr, Name);
} else {
OS << formatv(" {0}\n", Name);
}
}
static constexpr sys::Memory::ProtectionFlags ReadOnly =
static_cast<sys::Memory::ProtectionFlags>(sys::Memory::MF_READ);
@ -162,8 +186,9 @@ protected:
Expected<std::unique_ptr<Allocation>>
finalizeWorkingMemory(JITLinkContext &Ctx) override;
template <typename ELFT>
Error recordSection(StringRef Name,
std::unique_ptr<DebugObjectSection> Section);
std::unique_ptr<ELFDebugObjectSection<ELFT>> Section);
DebugObjectSection *getSection(StringRef Name);
private:
@ -319,8 +344,11 @@ void ELFDebugObject::reportSectionTargetMemoryRange(StringRef Name,
DebugObjSection->setTargetMemoryRange(TargetMem);
}
template <typename ELFT>
Error ELFDebugObject::recordSection(
StringRef Name, std::unique_ptr<DebugObjectSection> Section) {
StringRef Name, std::unique_ptr<ELFDebugObjectSection<ELFT>> Section) {
if (Error Err = Section->validateInBounds(this->getBuffer(), Name.data()))
return Err;
auto ItInserted = Sections.try_emplace(Name, std::move(Section));
if (!ItInserted.second)
return make_error<StringError>("Duplicate section",