diff --git a/llvm/lib/Object/MachOObjectFile.cpp b/llvm/lib/Object/MachOObjectFile.cpp --- a/llvm/lib/Object/MachOObjectFile.cpp +++ b/llvm/lib/Object/MachOObjectFile.cpp @@ -35,6 +35,7 @@ #include "llvm/Support/Format.h" #include "llvm/Support/Host.h" #include "llvm/Support/LEB128.h" +#include "llvm/Support/MathExtras.h" #include "llvm/Support/MemoryBufferRef.h" #include "llvm/Support/Path.h" #include "llvm/Support/SwapByteOrder.h" @@ -84,7 +85,9 @@ template static Expected getStructOrErr(const MachOObjectFile &O, const char *P) { // Don't read before the beginning or past the end of the file - if (P < O.getData().begin() || P + sizeof(T) > O.getData().end()) + bool Overflowed = false; + uintptr_t Ret = llvm::SaturatingAdd(P, sizeof(T), &Overflowed); + if (P < O.getData().begin() || Overflowed || Ret > O.getData().end()) return malformedError("Structure read out-of-range"); T Cmd; @@ -191,7 +194,12 @@ getLoadCommandInfo(const MachOObjectFile &Obj, const char *Ptr, uint32_t LoadCommandIndex) { if (auto CmdOrErr = getStructOrErr(Obj, Ptr)) { - if (CmdOrErr->cmdsize + Ptr > Obj.getData().end()) + bool Overflowed = false; + uintptr_t Ret = llvm::SaturatingAdd( + CmdOrErr->cmdsize, reinterpret_cast(Ptr), &Overflowed); + + if (Overflowed || + Ret > reinterpret_cast(Obj.getData().end())) return malformedError("load command " + Twine(LoadCommandIndex) + " extends past end of file"); if (CmdOrErr->cmdsize < 8) @@ -217,8 +225,28 @@ const MachOObjectFile::LoadCommandInfo &L) { unsigned HeaderSize = Obj.is64Bit() ? sizeof(MachO::mach_header_64) : sizeof(MachO::mach_header); - if (L.Ptr + L.C.cmdsize + sizeof(MachO::load_command) > - Obj.getData().data() + HeaderSize + Obj.getHeader().sizeofcmds) + + bool Overflowed = false; + // FIXME: Perhaps this validation on the Obj file should have been + // done somewhere else (earlier). + uint32_t LoadCmdsEnd = llvm::SaturatingAdd( + reinterpret_cast(Obj.getData().data()), HeaderSize, + &Overflowed); + assert(!Overflowed && "Load commands range extends past uint32_t type limit"); + LoadCmdsEnd = llvm::SaturatingAdd( + LoadCmdsEnd, Obj.getHeader().sizeofcmds, &Overflowed); + assert(!Overflowed && "Load commands range extends past uint32_t type limit"); + + uint32_t PtrEnd = llvm::SaturatingAdd( + reinterpret_cast(L.Ptr), L.C.cmdsize, &Overflowed); + if (!Overflowed) + PtrEnd = llvm::SaturatingAdd(PtrEnd, sizeof(MachO::load_command), + &Overflowed); + if (Overflowed) + return malformedError("load command " + Twine(LoadCommandIndex + 1) + + " extends past uint32_t type limit."); + + if (PtrEnd > LoadCmdsEnd) return malformedError("load command " + Twine(LoadCommandIndex + 1) + " extends past the end all load commands in the file"); return getLoadCommandInfo(Obj, L.Ptr + L.C.cmdsize, LoadCommandIndex + 1);