Skip to content

Commit 0931113

Browse files
author
Mariusz Borsa
committed
[Sanitizers][Darwin] Correct iterating of MachO load commands
The condition to stop iterating so far was to look for load command cmd field == 0. The iteration would continue past the commands area, and would finally find lc->cmd ==0, if lucky. Or crash with bus error, if out of luck. Correcting this by limiting the number of iterations to the count specified in mach_header(_64) ncmds field. rdar://143903403
1 parent 1df59b3 commit 0931113

File tree

2 files changed

+49
-13
lines changed

2 files changed

+49
-13
lines changed

compiler-rt/lib/sanitizer_common/sanitizer_procmaps_mac.cpp

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -334,9 +334,22 @@ static const load_command *NextCommand(const load_command *lc) {
334334
return (const load_command *)((const char *)lc + lc->cmdsize);
335335
}
336336

337-
static void FindUUID(const load_command *first_lc, u8 *uuid_output) {
338-
for (const load_command *lc = first_lc; lc->cmd != 0; lc = NextCommand(lc)) {
339-
if (lc->cmd != LC_UUID) continue;
337+
#ifdef MH_MAGIC_64
338+
static const size_t header_size = sizeof(mach_header_64);
339+
#else
340+
static const size_t header_size = sizeof(mach_header);
341+
#endif
342+
343+
static void FindUUID(const load_command *first_lc, const mach_header *hdr,
344+
u8 *uuid_output) {
345+
unsigned short curcmd = 0;
346+
for (const load_command *lc = first_lc; curcmd < hdr->ncmds;
347+
curcmd++, lc = NextCommand(lc)) {
348+
349+
CHECK_LT((const char*)lc, (const char*)hdr + header_size + hdr->sizeofcmds);
350+
351+
if (lc->cmd != LC_UUID)
352+
continue;
340353

341354
const uuid_command *uuid_lc = (const uuid_command *)lc;
342355
const uint8_t *uuid = &uuid_lc->uuid[0];
@@ -345,9 +358,16 @@ static void FindUUID(const load_command *first_lc, u8 *uuid_output) {
345358
}
346359
}
347360

348-
static bool IsModuleInstrumented(const load_command *first_lc) {
349-
for (const load_command *lc = first_lc; lc->cmd != 0; lc = NextCommand(lc)) {
350-
if (lc->cmd != LC_LOAD_DYLIB) continue;
361+
static bool IsModuleInstrumented(const load_command *first_lc,
362+
const mach_header *hdr) {
363+
unsigned short curcmd = 0;
364+
for (const load_command *lc = first_lc; curcmd < hdr->ncmds;
365+
curcmd++, lc = NextCommand(lc)) {
366+
367+
CHECK_LT((const char*)lc, (const char*)hdr + header_size + hdr->sizeofcmds);
368+
369+
if (lc->cmd != LC_LOAD_DYLIB)
370+
continue;
351371

352372
const dylib_command *dylib_lc = (const dylib_command *)lc;
353373
uint32_t dylib_name_offset = dylib_lc->dylib.name.offset;
@@ -394,9 +414,10 @@ bool MemoryMappingLayout::Next(MemoryMappedSegment *segment) {
394414
}
395415
}
396416
FindUUID((const load_command *)data_.current_load_cmd_addr,
397-
data_.current_uuid);
417+
hdr, data_.current_uuid);
398418
data_.current_instrumented = IsModuleInstrumented(
399-
(const load_command *)data_.current_load_cmd_addr);
419+
(const load_command *)data_.current_load_cmd_addr,
420+
hdr);
400421
}
401422

402423
while (data_.current_load_cmd_count > 0) {

compiler-rt/lib/sanitizer_common/tests/sanitizer_procmaps_mac_test.cpp

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,12 @@ class MemoryMappingLayoutMock final : public MemoryMappingLayout {
3737
.uuid = {}
3838
};
3939

40-
static constexpr char dylib_name[] = "libclang_rt.\0\0\0"; // 8 bytes aligned, padded with zeros per loader.h
40+
static constexpr char libclang_rt_dylib_name[] = "libclang_rt.\0\0\0"; // 8 bytes aligned, padded with zeros per loader.h
41+
static constexpr char uninstrumented_dylib_name[] = "uninst___rt.\0\0\0"; // 8 bytes aligned, padded with zeros per loader.h
42+
4143
static constexpr dylib_command mock_dylib_command = {
4244
.cmd = LC_LOAD_DYLIB,
43-
.cmdsize = sizeof(dylib_command) + sizeof(dylib_name),
45+
.cmdsize = sizeof(dylib_command) + sizeof(libclang_rt_dylib_name),
4446
.dylib = {
4547
.name = {
4648
.offset = sizeof(dylib_command)
@@ -59,7 +61,7 @@ class MemoryMappingLayoutMock final : public MemoryMappingLayout {
5961
std::vector<unsigned char> mock_header;
6062

6163
public:
62-
MemoryMappingLayoutMock(): MemoryMappingLayout(false) {
64+
MemoryMappingLayoutMock(bool instrumented): MemoryMappingLayout(false) {
6365
EXPECT_EQ(mock_uuid_command.cmdsize % 8, 0u);
6466
EXPECT_EQ(mock_dylib_command.cmdsize % 8, 0u);
6567

@@ -89,6 +91,7 @@ class MemoryMappingLayoutMock final : public MemoryMappingLayout {
8991
copy((unsigned char *)&mock_dylib_command,
9092
((unsigned char *)&mock_dylib_command) + sizeof(dylib_command), // as mock_dylib_command.cmdsize contains the following string
9193
back_inserter(mock_header));
94+
const char (&dylib_name)[16] = instrumented ? libclang_rt_dylib_name : uninstrumented_dylib_name;
9295
copy((unsigned char *)dylib_name,
9396
((unsigned char *)dylib_name) + sizeof(dylib_name),
9497
back_inserter(mock_header));
@@ -120,8 +123,20 @@ class MemoryMappingLayoutMock final : public MemoryMappingLayout {
120123
}
121124
};
122125

123-
TEST(MemoryMappingLayout, Next) {
124-
__sanitizer::MemoryMappingLayoutMock memory_mapping;
126+
TEST(MemoryMappingLayout, NextInstrumented) {
127+
__sanitizer::MemoryMappingLayoutMock memory_mapping(true);
128+
__sanitizer::MemoryMappedSegment segment;
129+
size_t size = memory_mapping.SizeOfLoadCommands();
130+
while (memory_mapping.Next(&segment)) {
131+
size_t offset = memory_mapping.CurrentLoadCommandOffset();
132+
EXPECT_LE(offset, size);
133+
}
134+
size_t final_offset = memory_mapping.CurrentLoadCommandOffset();
135+
EXPECT_EQ(final_offset, size); // All commands processed, no more, no less
136+
}
137+
138+
TEST(MemoryMappingLayout, NextUnInstrumented) {
139+
__sanitizer::MemoryMappingLayoutMock memory_mapping(false);
125140
__sanitizer::MemoryMappedSegment segment;
126141
size_t size = memory_mapping.SizeOfLoadCommands();
127142
while (memory_mapping.Next(&segment)) {

0 commit comments

Comments
 (0)