Skip to content

Commit de5a94a

Browse files
committed
[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 llvm-svn: 239080
1 parent 31d9c47 commit de5a94a

File tree

4 files changed

+28
-11
lines changed

4 files changed

+28
-11
lines changed

llvm/include/llvm/Object/Error.h

+1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ enum class object_error {
2828
parse_failed,
2929
unexpected_eof,
3030
bitcode_section_not_found,
31+
macho_small_load_command,
3132
};
3233

3334
inline std::error_code make_error_code(object_error e) {

llvm/lib/Object/Error.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ std::string _object_error_category::message(int EV) const {
4444
return "The end of the file was unexpectedly encountered";
4545
case object_error::bitcode_section_not_found:
4646
return "Bitcode section not found in object file";
47+
case object_error::macho_small_load_command:
48+
return "Mach-O load command with size < 8 bytes";
4749
}
4850
llvm_unreachable("An enumerator of object_error does not have a message "
4951
"defined.");

llvm/lib/Object/MachOObjectFile.cpp

+23-9
Original file line numberDiff line numberDiff line change
@@ -194,24 +194,27 @@ static uint32_t getSectionFlags(const MachOObjectFile *O,
194194
return Sect.flags;
195195
}
196196

197-
static MachOObjectFile::LoadCommandInfo
197+
static ErrorOr<MachOObjectFile::LoadCommandInfo>
198198
getLoadCommandInfo(const MachOObjectFile *Obj, const char *Ptr) {
199+
auto CmdOrErr = getStructOrErr<MachO::load_command>(Obj, Ptr);
200+
if (!CmdOrErr)
201+
return CmdOrErr.getError();
202+
if (CmdOrErr->cmdsize < 8)
203+
return object_error::macho_small_load_command;
199204
MachOObjectFile::LoadCommandInfo Load;
200205
Load.Ptr = Ptr;
201-
Load.C = getStruct<MachO::load_command>(Obj, Load.Ptr);
202-
if (Load.C.cmdsize < 8)
203-
report_fatal_error("Load command with size < 8 bytes.");
206+
Load.C = CmdOrErr.get();
204207
return Load;
205208
}
206209

207-
static MachOObjectFile::LoadCommandInfo
210+
static ErrorOr<MachOObjectFile::LoadCommandInfo>
208211
getFirstLoadCommandInfo(const MachOObjectFile *Obj) {
209212
unsigned HeaderSize = Obj->is64Bit() ? sizeof(MachO::mach_header_64)
210213
: sizeof(MachO::mach_header);
211214
return getLoadCommandInfo(Obj, getPtr(Obj, HeaderSize));
212215
}
213216

214-
static MachOObjectFile::LoadCommandInfo
217+
static ErrorOr<MachOObjectFile::LoadCommandInfo>
215218
getNextLoadCommandInfo(const MachOObjectFile *Obj,
216219
const MachOObjectFile::LoadCommandInfo &L) {
217220
return getLoadCommandInfo(Obj, L.Ptr + L.C.cmdsize);
@@ -251,7 +254,12 @@ MachOObjectFile::MachOObjectFile(MemoryBufferRef Object, bool IsLittleEndian,
251254
MachO::LoadCommandType SegmentLoadType = is64Bit() ?
252255
MachO::LC_SEGMENT_64 : MachO::LC_SEGMENT;
253256

254-
LoadCommandInfo Load = getFirstLoadCommandInfo(this);
257+
auto LoadOrErr = getFirstLoadCommandInfo(this);
258+
if (!LoadOrErr) {
259+
EC = LoadOrErr.getError();
260+
return;
261+
}
262+
LoadCommandInfo Load = LoadOrErr.get();
255263
for (unsigned I = 0; I < LoadCommandCount; ++I) {
256264
LoadCommands.push_back(Load);
257265
if (Load.C.cmd == MachO::LC_SYMTAB) {
@@ -318,8 +326,14 @@ MachOObjectFile::MachOObjectFile(MemoryBufferRef Object, bool IsLittleEndian,
318326
Load.C.cmd == MachO::LC_LOAD_UPWARD_DYLIB) {
319327
Libraries.push_back(Load.Ptr);
320328
}
321-
if (I < LoadCommandCount - 1)
322-
Load = getNextLoadCommandInfo(this, Load);
329+
if (I < LoadCommandCount - 1) {
330+
auto LoadOrErr = getNextLoadCommandInfo(this, Load);
331+
if (!LoadOrErr) {
332+
EC = LoadOrErr.getError();
333+
return;
334+
}
335+
Load = LoadOrErr.get();
336+
}
323337
}
324338
assert(LoadCommands.size() == LoadCommandCount);
325339
}

llvm/test/Object/macho-invalid.test

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,13 @@ RUN: llvm-objdump -private-headers %p/Inputs/macho-invalid-zero-ncmds
33

44
RUN: not llvm-objdump -private-headers %p/Inputs/macho64-invalid-incomplete-load-command 2>&1 \
55
RUN: | FileCheck -check-prefix INCOMPLETE-LOADC %s
6-
INCOMPLETE-LOADC: Malformed MachO file
6+
INCOMPLETE-LOADC: Invalid data was encountered while parsing the file.
77

88
RUN: not llvm-objdump -private-headers %p/Inputs/macho-invalid-too-small-load-command 2>&1 \
99
RUN: | FileCheck -check-prefix SMALL-LOADC-SIZE %s
1010
RUN: not llvm-objdump -private-headers %p/Inputs/macho64-invalid-too-small-load-command 2>&1 \
1111
RUN: | FileCheck -check-prefix SMALL-LOADC-SIZE %s
12-
SMALL-LOADC-SIZE: Load command with size < 8 bytes
12+
SMALL-LOADC-SIZE: Mach-O load command with size < 8 bytes
1313

1414
RUN: not llvm-objdump -private-headers %p/Inputs/macho-invalid-too-small-segment-load-command 2>&1 \
1515
RUN: | FileCheck -check-prefix SMALL-SEGLOADC-SIZE %s

0 commit comments

Comments
 (0)