diff --git a/objectivec/objc.cpp b/objectivec/objc.cpp index 6575ed51b7..1b53a36691 100644 --- a/objectivec/objc.cpp +++ b/objectivec/objc.cpp @@ -6,6 +6,10 @@ #define RELEASE_ASSERT(condition) ((condition) ? (void)0 : (std::abort(), (void)0)) +#define MAX_PROTOCOL_COUNT 0x1000 +#define MAX_METHOD_LIST_COUNT 0x1000 +#define MAX_IVAR_LIST_COUNT 0x1000 + using namespace BinaryNinja; namespace { @@ -847,6 +851,11 @@ void ObjCProcessor::LoadProtocols(ObjCReader* reader, Ref
listSection) "protoProtocols_" + protocolName, protocol.protocols, true); reader->Seek(protocol.protocols); uint32_t count = reader->Read64(); + if (count > MAX_PROTOCOL_COUNT) + { + m_logger->LogWarn("List of protocols at 0x%llx has too large a count of 0x%x, skipping...", protocol.protocols, count); + continue; + } view_ptr_t addr = reader->GetOffset(); for (uint32_t j = 0; j < count; j++) { @@ -928,7 +937,7 @@ void ObjCProcessor::ReadListOfMethodLists(ObjCReader* reader, ClassBase& cls, st head.entsizeAndFlags = reader->Read32(); head.count = reader->Read32(); - if (head.count > 0x1000) + if (head.count > MAX_METHOD_LIST_COUNT) { m_logger->LogError("List of method lists at 0x%llx has an invalid count of 0x%x", start, head.count); return; @@ -962,7 +971,7 @@ void ObjCProcessor::ReadMethodList(ObjCReader* reader, ClassBase& cls, std::stri head.entsizeAndFlags = reader->Read32(); head.count = reader->Read32(); - if (head.count > 0x1000) + if (head.count > MAX_METHOD_LIST_COUNT) { m_logger->LogError("Method list at 0x%llx has an invalid count of 0x%x", start, head.count); return; @@ -1066,6 +1075,11 @@ void ObjCProcessor::ReadIvarList(ObjCReader* reader, ClassBase& cls, std::string ivar_list_t head; head.entsizeAndFlags = reader->Read32(); head.count = reader->Read32(); + if (head.count > MAX_IVAR_LIST_COUNT) + { + m_logger->LogWarn("Ivar list at 0x%llx has an invalid count of 0x%x, skipping..", start, head.count); + return; + } auto addressSize = m_data->GetAddressSize(); DefineObjCSymbol(DataSymbol, m_typeNames.ivarList, "ivar_list_" + std::string(name), start, true); for (unsigned i = 0; i < head.count; i++) @@ -1681,6 +1695,11 @@ void ObjCProcessor::ProcessCFStrings() uint64_t flags = reader->ReadPointer(); auto strLoc = ReadPointerAccountingForRelocations(reader.get()); auto size = reader->ReadPointer(); + if (size > cfstrings->GetEnd() || reader->GetOffset() > cfstrings->GetEnd() - size) + { + m_logger->LogWarn("CFString at 0x%llx has invalid size 0x%llx, skipping...", i, size); + continue; + } std::string str; if (flags & 0b10000) // UTF16 { diff --git a/platform/windows/platform_windows.cpp b/platform/windows/platform_windows.cpp index b4b7c55d65..612e5cf5e4 100644 --- a/platform/windows/platform_windows.cpp +++ b/platform/windows/platform_windows.cpp @@ -92,6 +92,7 @@ class WindowsX64Platform: public Platform { uint32_t m_gsbase; Ref m_teb; + std::mutex m_tebMutex; public: WindowsX64Platform(Architecture* arch): Platform(arch, "windows-x86_64") @@ -113,6 +114,8 @@ class WindowsX64Platform: public Platform virtual void BinaryViewInit(BinaryView* view) override { + // Locking here so that if we have two views in BinaryViewInit at once we don't race to init m_teb. + std::lock_guard lock(m_tebMutex); if (!m_teb) m_teb = Type::PointerType(GetArchitecture()->GetAddressSize(), Type::NamedType(QualifiedName("TEB"), GetTypeByName(QualifiedName("TEB")))); } diff --git a/plugins/rtti/itanium.cpp b/plugins/rtti/itanium.cpp index c805343de4..a2ddc59a45 100644 --- a/plugins/rtti/itanium.cpp +++ b/plugins/rtti/itanium.cpp @@ -697,7 +697,7 @@ void ItaniumRTTIProcessor::ProcessRTTI() int failedAttempts = 0; for (uint64_t currAddr = section->GetStart(); currAddr <= section->GetEnd() - maxTypeInfoSize; currAddr += addrSize) { - if (bgTask->IsCancelled()) + if (bgTask->IsCancelled() || !m_view->IsValidOffset(currAddr)) break; try { diff --git a/plugins/warp/ui/plugin.cpp b/plugins/warp/ui/plugin.cpp index 93900ed9e2..fad46a98fa 100644 --- a/plugins/warp/ui/plugin.cpp +++ b/plugins/warp/ui/plugin.cpp @@ -9,6 +9,7 @@ #include #include +#include #include using namespace BinaryNinja; @@ -170,11 +171,13 @@ WarpSidebarWidget::WarpSidebarWidget(BinaryViewRef data) : SidebarWidget("WARP") this->setLayout(layout); // Do a full update if analysis has been done, otherwise we may persist old data and not have new data. - m_analysisEvent = new AnalysisCompletionEvent(m_data, [this]() { ExecuteOnMainThread([this]() { Update(); }); }); + m_analysisEvent = new AnalysisCompletionEvent(m_data, [this]() { + QMetaObject::invokeMethod(this, [this]() { Update(); }); + }); m_fetcher = WarpFetcher::Global(); m_callbackId = m_fetcher->AddCompletionCallback([this]() { - ExecuteOnMainThread([this]() { + QMetaObject::invokeMethod(this, [this]() { // Instead of doing a full update after fetching, we only want to make sure the current function has // up-to-date matches, since the other two tabs (all matches, container list) do not get populated with // additional information or manage their own updates (e.g. container source list). diff --git a/rust/src/architecture.rs b/rust/src/architecture.rs index df2e66b74d..d96dc34b5f 100644 --- a/rust/src/architecture.rs +++ b/rust/src/architecture.rs @@ -1776,7 +1776,11 @@ where }; let mut ctx = unsafe { - FunctionLifterContext::from_raw_with_arch(function, context, Some(*custom_arch.as_ref())) + FunctionLifterContext::from_raw_with_arch( + function, + context, + Some(*custom_arch.as_ref()), + ) }; custom_arch.lift_function(llil, &mut ctx) } diff --git a/view/elf/elfview.cpp b/view/elf/elfview.cpp index c54663d485..d5ff0ef4b2 100644 --- a/view/elf/elfview.cpp +++ b/view/elf/elfview.cpp @@ -1154,6 +1154,11 @@ bool ElfView::Init() 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)) + { + m_logger->LogWarn("ELF GOT entry %" PRIx64 " is invalid", gotEntry); + break; + } ElfSymbolTableEntry entry; if (!ParseSymbolTableEntry(virtualReader, entry, i, m_auxSymbolTable, m_dynamicStringTable, true)) diff --git a/view/pe/peview.cpp b/view/pe/peview.cpp index 718822ba99..a793eeb3a3 100644 --- a/view/pe/peview.cpp +++ b/view/pe/peview.cpp @@ -1753,10 +1753,15 @@ bool PEView::Init() } } - if (m_dataDirs[IMAGE_DIRECTORY_ENTRY_EXCEPTION].size % entrySize) + const auto& exceptionDir = m_dataDirs[IMAGE_DIRECTORY_ENTRY_EXCEPTION]; + if (exceptionDir.size % entrySize) throw PEFormatException("invalid table size"); - numExceptionEntries = m_dataDirs[IMAGE_DIRECTORY_ENTRY_EXCEPTION].size / entrySize; + const auto imageSize = GetEnd() - GetStart(); + if ((exceptionDir.virtualAddress > imageSize) + || (exceptionDir.size > (imageSize - exceptionDir.virtualAddress))) + throw PEFormatException("too many exception entries, table size exceeds available memory range"); + numExceptionEntries = exceptionDir.size / entrySize; // This DataVariable can end up creating a large array and rendering this in LinearView currently has performance implications // So instead we just create separate structures not in an array Ref exceptionEntryStruct = exceptionEntryBuilder.Finalize();