From 7e699dce03ed9ac10be159f72490ab6d31e7b27e Mon Sep 17 00:00:00 2001 From: Alexey Samsonov Date: Thu, 4 Jun 2015 19:57:46 +0000 Subject: [PATCH] [Object, MachO] Don't crash on invalid MachO load commands. Summary: Currently all load commands are parsed in MachOObjectFile constructor. If the next load command cannot be parsed, or if command size is too small, properly report it through the error code and fail to construct the object, instead of crashing the program. Test Plan: regression test suite Reviewers: rafael, filcab Subscribers: llvm-commits git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@239080 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/Object/Error.h | 1 + lib/Object/Error.cpp | 2 ++ lib/Object/MachOObjectFile.cpp | 32 +++++++++++++++++++++++--------- test/Object/macho-invalid.test | 4 ++-- 4 files changed, 28 insertions(+), 11 deletions(-) diff --git a/include/llvm/Object/Error.h b/include/llvm/Object/Error.h index 90c2bd74b43..13a14aa09c7 100644 --- a/include/llvm/Object/Error.h +++ b/include/llvm/Object/Error.h @@ -28,6 +28,7 @@ enum class object_error { parse_failed, unexpected_eof, bitcode_section_not_found, + macho_small_load_command, }; inline std::error_code make_error_code(object_error e) { diff --git a/lib/Object/Error.cpp b/lib/Object/Error.cpp index d2daab72d58..1c8dad80b0a 100644 --- a/lib/Object/Error.cpp +++ b/lib/Object/Error.cpp @@ -44,6 +44,8 @@ std::string _object_error_category::message(int EV) const { return "The end of the file was unexpectedly encountered"; case object_error::bitcode_section_not_found: return "Bitcode section not found in object file"; + case object_error::macho_small_load_command: + return "Mach-O load command with size < 8 bytes"; } llvm_unreachable("An enumerator of object_error does not have a message " "defined."); diff --git a/lib/Object/MachOObjectFile.cpp b/lib/Object/MachOObjectFile.cpp index c1d13838444..3262c6c26ab 100644 --- a/lib/Object/MachOObjectFile.cpp +++ b/lib/Object/MachOObjectFile.cpp @@ -194,24 +194,27 @@ static uint32_t getSectionFlags(const MachOObjectFile *O, return Sect.flags; } -static MachOObjectFile::LoadCommandInfo +static ErrorOr getLoadCommandInfo(const MachOObjectFile *Obj, const char *Ptr) { + auto CmdOrErr = getStructOrErr(Obj, Ptr); + if (!CmdOrErr) + return CmdOrErr.getError(); + if (CmdOrErr->cmdsize < 8) + return object_error::macho_small_load_command; MachOObjectFile::LoadCommandInfo Load; Load.Ptr = Ptr; - Load.C = getStruct(Obj, Load.Ptr); - if (Load.C.cmdsize < 8) - report_fatal_error("Load command with size < 8 bytes."); + Load.C = CmdOrErr.get(); return Load; } -static MachOObjectFile::LoadCommandInfo +static ErrorOr getFirstLoadCommandInfo(const MachOObjectFile *Obj) { unsigned HeaderSize = Obj->is64Bit() ? sizeof(MachO::mach_header_64) : sizeof(MachO::mach_header); return getLoadCommandInfo(Obj, getPtr(Obj, HeaderSize)); } -static MachOObjectFile::LoadCommandInfo +static ErrorOr getNextLoadCommandInfo(const MachOObjectFile *Obj, const MachOObjectFile::LoadCommandInfo &L) { return getLoadCommandInfo(Obj, L.Ptr + L.C.cmdsize); @@ -251,7 +254,12 @@ MachOObjectFile::MachOObjectFile(MemoryBufferRef Object, bool IsLittleEndian, MachO::LoadCommandType SegmentLoadType = is64Bit() ? MachO::LC_SEGMENT_64 : MachO::LC_SEGMENT; - LoadCommandInfo Load = getFirstLoadCommandInfo(this); + auto LoadOrErr = getFirstLoadCommandInfo(this); + if (!LoadOrErr) { + EC = LoadOrErr.getError(); + return; + } + LoadCommandInfo Load = LoadOrErr.get(); for (unsigned I = 0; I < LoadCommandCount; ++I) { LoadCommands.push_back(Load); if (Load.C.cmd == MachO::LC_SYMTAB) { @@ -318,8 +326,14 @@ MachOObjectFile::MachOObjectFile(MemoryBufferRef Object, bool IsLittleEndian, Load.C.cmd == MachO::LC_LOAD_UPWARD_DYLIB) { Libraries.push_back(Load.Ptr); } - if (I < LoadCommandCount - 1) - Load = getNextLoadCommandInfo(this, Load); + if (I < LoadCommandCount - 1) { + auto LoadOrErr = getNextLoadCommandInfo(this, Load); + if (!LoadOrErr) { + EC = LoadOrErr.getError(); + return; + } + Load = LoadOrErr.get(); + } } assert(LoadCommands.size() == LoadCommandCount); } diff --git a/test/Object/macho-invalid.test b/test/Object/macho-invalid.test index fd09abf338b..55b186dedd3 100644 --- a/test/Object/macho-invalid.test +++ b/test/Object/macho-invalid.test @@ -3,13 +3,13 @@ RUN: llvm-objdump -private-headers %p/Inputs/macho-invalid-zero-ncmds RUN: not llvm-objdump -private-headers %p/Inputs/macho64-invalid-incomplete-load-command 2>&1 \ RUN: | FileCheck -check-prefix INCOMPLETE-LOADC %s -INCOMPLETE-LOADC: Malformed MachO file +INCOMPLETE-LOADC: Invalid data was encountered while parsing the file. RUN: not llvm-objdump -private-headers %p/Inputs/macho-invalid-too-small-load-command 2>&1 \ RUN: | FileCheck -check-prefix SMALL-LOADC-SIZE %s RUN: not llvm-objdump -private-headers %p/Inputs/macho64-invalid-too-small-load-command 2>&1 \ RUN: | FileCheck -check-prefix SMALL-LOADC-SIZE %s -SMALL-LOADC-SIZE: Load command with size < 8 bytes +SMALL-LOADC-SIZE: Mach-O load command with size < 8 bytes RUN: not llvm-objdump -private-headers %p/Inputs/macho-invalid-too-small-segment-load-command 2>&1 \ RUN: | FileCheck -check-prefix SMALL-SEGLOADC-SIZE %s -- 2.34.1