Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
37 changes: 34 additions & 3 deletions llvm/lib/ObjectYAML/MachOEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,26 @@
#include "llvm/Support/Error.h"
#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/LEB128.h"
#include "llvm/Support/YAMLTraits.h"
#include "llvm/Support/SystemZ/zOSSupport.h"
#include "llvm/Support/WithColor.h"
#include "llvm/Support/YAMLTraits.h"
#include "llvm/Support/raw_ostream.h"

using namespace llvm;

namespace {

static const char *getLoadCommandName(uint32_t cmd) {
switch (cmd) {
#define HANDLE_LOAD_COMMAND(LCName, LCValue, LCStruct) \
case MachO::LCName: \
return #LCName;
#include "llvm/BinaryFormat/MachO.def"
default:
return nullptr;
}
}

class MachOWriter {
public:
MachOWriter(MachOYAML::Object &Obj) : Obj(Obj), fileStart(0) {
Expand Down Expand Up @@ -244,7 +256,8 @@ void MachOWriter::ZeroToOffset(raw_ostream &OS, size_t Offset) {
}

void MachOWriter::writeLoadCommands(raw_ostream &OS) {
for (auto &LC : Obj.LoadCommands) {
for (size_t i = 0; i < Obj.LoadCommands.size(); ++i) {
auto &LC = Obj.LoadCommands[i];
size_t BytesWritten = 0;
llvm::MachO::macho_load_command Data = LC.Data;

Expand Down Expand Up @@ -285,7 +298,25 @@ void MachOWriter::writeLoadCommands(raw_ostream &OS) {

// Fill remaining bytes with 0. This will only get hit in partially
// specified test cases.
auto BytesRemaining = LC.Data.load_command_data.cmdsize - BytesWritten;
// Prevent integer underflow if BytesWritten exceeds cmdsize.
if (BytesWritten > LC.Data.load_command_data.cmdsize) {
std::string Name;
const char *NameCStr = getLoadCommandName(LC.Data.load_command_data.cmd);
if (NameCStr)
Name = NameCStr;
else
Name = ("(0x" + Twine::utohexstr(LC.Data.load_command_data.cmd) + ")")
.str();

WithColor::warning() << "load command " << i << " " << Name
<< " cmdsize too small ("
<< LC.Data.load_command_data.cmdsize
<< " bytes) for actual size (" << BytesWritten
<< " bytes)\n";
}
auto BytesRemaining = (BytesWritten < LC.Data.load_command_data.cmdsize)
? LC.Data.load_command_data.cmdsize - BytesWritten
: 0;
if (BytesRemaining > 0) {
ZeroFillBytes(OS, BytesRemaining);
}
Expand Down
55 changes: 55 additions & 0 deletions llvm/test/ObjectYAML/MachO/load-cmdsize-too-small.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
## Test that yaml2obj handles load commands with cmdsize smaller than the
## actual structure size without crashing (due to integer underflow).

## Test with a known load command (LC_SEGMENT_64).
# RUN: yaml2obj %s --docnum=1 -o %t1 2>&1 | FileCheck %s --check-prefix=WARNING-KNOWN
# RUN: not llvm-readobj --file-headers %t1 2>&1 | FileCheck %s --check-prefix=MALFORMED

# WARNING-KNOWN: warning: load command 0 LC_SEGMENT_64 cmdsize too small (56 bytes) for actual size (72 bytes)

# MALFORMED: error: {{.*}}: truncated or malformed object (load command 0 LC_SEGMENT_64 cmdsize too small)

--- !mach-o
FileHeader:
magic: 0xFEEDFACF
cputype: 0x01000007
cpusubtype: 0x00000003
filetype: 0x00000001
ncmds: 1
sizeofcmds: 56
flags: 0x00002000
reserved: 0x00000000
LoadCommands:
- cmd: LC_SEGMENT_64
cmdsize: 56 ## Should be 72 for LC_SEGMENT_64
segname: '__TEXT'
vmaddr: 0x1000
vmsize: 0x10
fileoff: 0
filesize: 0
maxprot: 7
initprot: 5
nsects: 0
flags: 0
...

## Test with an unknown load command value.
# RUN: yaml2obj %s --docnum=2 -o %t2 2>&1 | FileCheck %s --check-prefix=WARNING-UNKNOWN

# WARNING-UNKNOWN: warning: load command 0 (0xdeadbeef) cmdsize too small (8 bytes) for actual size (20 bytes)

--- !mach-o
FileHeader:
magic: 0xFEEDFACF
cputype: 0x01000007
cpusubtype: 0x00000003
filetype: 0x00000001
ncmds: 1
sizeofcmds: 20
flags: 0x00002000
reserved: 0x00000000
LoadCommands:
- cmd: 0xDEADBEEF
cmdsize: 8
PayloadBytes: [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C]
...