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
25 changes: 13 additions & 12 deletions Crashlytics/Crashlytics/Unwind/Dwarf/FIRCLSDwarfExpressionMachine.c
Original file line number Diff line number Diff line change
Expand Up @@ -401,32 +401,33 @@ static bool FIRCLSDwarfExpressionMachineExecute_swap(FIRCLSDwarfExpressionMachin

static bool FIRCLSDwarfExpressionMachineExecute_deref_size(FIRCLSDwarfExpressionMachine *machine) {
// pop stack, dereference variable sized value, push result
const void *address = (const void *)FIRCLSDwarfExpressionMachineStackPop(machine);
const intptr_t address = FIRCLSDwarfExpressionMachineStackPop(machine);
const uint8_t readSize = FIRCLSParseUint8AndAdvance(&machine->dataCursor);
intptr_t value = 0;

FIRCLSSDKLog("DW_OP_deref_size %p size %u\n", address, readSize);
FIRCLSSDKLog("DW_OP_deref_size %p size %u\n", (void *)address, readSize);

switch (readSize) {
case 1:
value = FIRCLSParseUint8AndAdvance(&address);
break;
case 2:
value = FIRCLSParseUint16AndAdvance(&address);
break;
case 4:
value = FIRCLSParseUint32AndAdvance(&address);
break;
case 8:
// this is a little funky, as an 8 here really doesn't make sense for 32-bit platforms
value = (intptr_t)FIRCLSParseUint64AndAdvance(&address);
// 8 is a little funky, as it really doesn't make sense for 32-bit platforms
break;
default:
FIRCLSSDKLog("Error: unrecognized DW_OP_deref_size argument %x\n", readSize);
return false;
}

return FIRCLSDwarfExpressionMachineStackPush(machine, value);
// The address is popped off the expression stack, so it is fully controlled by
// the CFI program. Read it through the validated path like DW_OP_deref does
// instead of dereferencing it directly.
uint64_t buffer = 0;
if (!FIRCLSReadMemory(address, &buffer, readSize)) {
FIRCLSSDKLog("Error: DW_OP_deref_size failed to read memory\n");
return false;
}

return FIRCLSDwarfExpressionMachineStackPush(machine, (intptr_t)buffer);
}

static bool FIRCLSDwarfExpressionMachineExecute_ne(FIRCLSDwarfExpressionMachine *machine) {
Expand Down
24 changes: 24 additions & 0 deletions Crashlytics/UnitTests/FIRCLSDwarfExpressionTests.m
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#import <XCTest/XCTest.h>

#include "Crashlytics/Crashlytics/Unwind/Dwarf/FIRCLSDwarfExpressionMachine.h"
#include "Crashlytics/third_party/libunwind/dwarf.h"

@interface FIRCLSDwarfExpressionTests : XCTestCase

Expand Down Expand Up @@ -137,6 +138,29 @@ - (void)testDwarfExpressionMachineInit {
XCTAssertEqual(FIRCLSDwarfExpressionStackPeek(&machine.stack), 42);
}

- (void)testDwarfDerefSizeReadsValidAddress {
uint32_t target = 0xABCD1234;
// DW_OP_deref_size with a 4-byte read argument; the address is on the stack.
uint8_t program[] = {DW_OP_deref_size, 4};
FIRCLSThreadContext registers = {0};
FIRCLSDwarfExpressionMachine machine;

XCTAssert(FIRCLSDwarfExpressionMachineInit(&machine, program, &registers, (intptr_t)&target));
XCTAssert(FIRCLSDwarfExpressionMachineExecuteNextOpcode(&machine));
XCTAssertEqual(FIRCLSDwarfExpressionStackPeek(&machine.stack), (intptr_t)0xABCD1234);
}

- (void)testDwarfDerefSizeRejectsUnreadableAddress {
// The address to dereference is taken from the stack. Feed one that is not
// readable and confirm the opcode reports failure instead of faulting.
uint8_t program[] = {DW_OP_deref_size, 4};
FIRCLSThreadContext registers = {0};
FIRCLSDwarfExpressionMachine machine;

XCTAssert(FIRCLSDwarfExpressionMachineInit(&machine, program, &registers, (intptr_t)0x1));
XCTAssertFalse(FIRCLSDwarfExpressionMachineExecuteNextOpcode(&machine));
}

#endif

@end
Loading