Skip to content
Open
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 77 additions & 7 deletions view/elf/elfview.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,28 @@ void BinaryNinja::InitElfViewType()
"ignore" : ["SettingsProjectScope", "SettingsResourceScope"]
})~");

settings->RegisterSetting("files.elf.maxMipsGotMB",
R"({
"title" : "Maximum MIPS GOT Data Size in MB",
"type" : "number",
"default" : 4,
"minValue" : 0,
"maxValue" : 64,
"description" : "Maximum total GOT data size in megabytes to process in MIPS ELF files",
"ignore" : ["SettingsProjectScope"]
})");

settings->RegisterSetting("files.elf.maxStringTableTypeSizeMB",
R"~({
"title" : "Maximum ELF String Table Size for Type Application (MB)",
"type" : "number",
"default" : 4,
"minValue" : 0,
"maxValue" : 256,
"description" : "Maximum string table size in megabytes when applying types from string tables",
"ignore" : ["SettingsProjectScope"]
})~");

}


Expand Down Expand Up @@ -1149,14 +1171,34 @@ bool ElfView::Init()
{
if (mipsSymValid && (gotStart != 0))
{
for (size_t i = 2; i < localMipsSyms; i++)
const uint64_t entrySize = m_elf32 ? 4 : 8;
Ref<Settings> viewSettings = Settings::Instance();
const uint64_t mbBudget = viewSettings->Get<uint64_t>("files.elf.maxMipsGotMB", this);
const uint64_t entryBudget = (mbBudget * 1024 * 1024) / entrySize;

// Find the file-backed region containing gotStart once, so the loop needs no per-entry check.
uint64_t gotFileEnd = gotStart;
for (const auto& hdr : m_programHeaders)
{
m_gotEntryLocations.emplace(gotStart + i * (m_elf32 ? 4 : 8));
if (hdr.type != ELF_PT_LOAD || hdr.fileSize == 0 || hdr.fileSize > UINT64_MAX - hdr.virtualAddress)
continue;
uint64_t segEnd = hdr.virtualAddress + hdr.fileSize;
if (hdr.virtualAddress > gotStart || gotStart >= segEnd)
continue;
// Only trust this segment's declared extent up to what the file actually backs.
if (hdr.fileSize > UINT64_MAX - hdr.offset || hdr.offset + hdr.fileSize > (uint64_t)GetParentView()->GetLength())
continue;
gotFileEnd = segEnd;
break;
}
const uint64_t maxFromFile = (gotFileEnd > gotStart) ? (gotFileEnd - gotStart) / entrySize : 0;
const uint64_t limit = std::min({localMipsSyms, entryBudget, maxFromFile});
for (size_t i = 2; i < limit; i++)
m_gotEntryLocations.emplace(gotStart + i * entrySize);
for (uint64_t i = firstMipsSym; i < (m_auxSymbolTable.size / (m_elf32 ? 16 : 24)); i++)
{
uint64_t gotEntry = gotStart + ((localMipsSyms + i - firstMipsSym) * (m_elf32 ? 4 : 8));
if (!IsValidOffset(gotEntry))
uint64_t gotEntry = gotStart + ((localMipsSyms + i - firstMipsSym) * entrySize);
if (!IsRangeBackedByFile(gotEntry, entrySize))
{
m_logger->LogWarn("ELF GOT entry %" PRIx64 " is invalid", gotEntry);
break;
Expand Down Expand Up @@ -1796,7 +1838,7 @@ bool ElfView::Init()
}

// Perform fixup processing on the local GOT entries if the view is relocatable.
if (m_relocatable)
if (m_relocatable && localMipsSyms > 0)
{
uint64_t lastLocalGotEntry = gotStart + (localMipsSyms - 1) * (m_elf32 ? 4 : 8);
for (auto gotEntry : m_gotEntryLocations)
Expand Down Expand Up @@ -2665,6 +2707,14 @@ void ElfView::DefineElfSymbol(BNSymbolType type, const string& incomingName, uin
void ElfView::ApplyTypesToParentStringTable(const Elf64SectionHeader& section, const bool offset)
{
m_logger->LogInfo("Found string table of size %p at offset %p", section.size, section.offset);
if (section.size == 0 ||
section.size > UINT64_MAX - section.offset ||
section.offset + section.size > GetParentView()->GetLength())
return;
Ref<Settings> viewSettings = Settings::Instance();
const uint64_t sizeBudget = viewSettings->Get<uint64_t>("files.elf.maxStringTableTypeSizeMB", this) * 1024 * 1024;
if (section.size > sizeBudget)
return;
DataBuffer buffer = GetParentView()->ReadBuffer(section.offset, section.size);
if (buffer.GetLength() != section.size)
return;
Expand Down Expand Up @@ -2734,7 +2784,7 @@ void ElfView::ApplyTypesToStringTable(const Elf64SectionHeader& section, const i

string ElfView::ReadStringTable(BinaryReader& reader, const Elf64SectionHeader& section, uint64_t offset)
{
if (offset == 0 || offset > section.size)
if (offset == 0 || offset >= section.size || section.size > GetParentView()->GetLength())
return "";

auto itr = m_stringTableCache.find(section.offset);
Expand All @@ -2754,7 +2804,27 @@ string ElfView::ReadStringTable(BinaryReader& reader, const Elf64SectionHeader&
}

const std::vector<char>& tableCache = itr->second;
return std::string(&tableCache[offset], strlen(tableCache.data() + offset));
if (offset >= tableCache.size()) {
m_logger->LogError("Unable to read string from table cache offset: 0x%" PRIx64 " size: 0x%" PRIx64, section.offset, section.size);
return "";
}
return std::string(&tableCache[offset], strnlen(tableCache.data() + offset, tableCache.size() - offset));
}


// Returns true only if the entire range [start, start+size) is backed by file data.
bool ElfView::IsRangeBackedByFile(uint64_t start, uint64_t size) const
{
if (size == 0)
return false;
if (size > UINT64_MAX - start)
return false;
for (uint64_t offset = start; offset < start + size; offset++)

@emesare emesare Aug 19, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems quite expensive, would it not be okay to just check the start and end? I see you mention it in the PR description but what is this guarding against?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the feedback — I've adopted your suggested fix, pushed in d186a75.

{
if (!IsOffsetBackedByFile(offset))
return false;
}
return true;
}


Expand Down
2 changes: 2 additions & 0 deletions view/elf/elfview.h
Original file line number Diff line number Diff line change
Expand Up @@ -527,6 +527,8 @@ namespace BinaryNinja
void DefineElfSymbol(BNSymbolType type, const std::string& name, uint64_t addr, bool gotEntry,
BNSymbolBinding binding, size_t size = 0, const Confidence<Ref<Type>>& typeObj = nullptr);

bool IsRangeBackedByFile(uint64_t start, uint64_t size) const;

void ApplyTypesToParentStringTable(const Elf64SectionHeader& section, const bool offset = true);
void ApplyTypesToStringTable(const Elf64SectionHeader& section, const int64_t imageBaseAdjustment, const bool offset = true);
std::string ReadStringTable(BinaryReader& view, const Elf64SectionHeader& section, uint64_t offset);
Expand Down
Loading