Skip to content

Commit d22c92e

Browse files
committed
Conforming to Mach IPC security restrictions
1 parent 3c872e2 commit d22c92e

File tree

3 files changed

+73
-19
lines changed

3 files changed

+73
-19
lines changed

Crashlytics/CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
# Unrelased
2+
- [fixed] Conformed to Mach IPC security restrictions.
3+
14
# 12.4.0
25
- [fixed] Make set development platform APIs to chain on Crashlytics context init promise.
36

Crashlytics/Crashlytics/Handlers/FIRCLSMachException.c

Lines changed: 61 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -33,18 +33,18 @@
3333
static void* FIRCLSMachExceptionServer(void* argument);
3434
static bool FIRCLSMachExceptionThreadStart(FIRCLSMachExceptionReadContext* context);
3535
static bool FIRCLSMachExceptionReadMessage(FIRCLSMachExceptionReadContext* context,
36-
MachExceptionMessage* message);
36+
MachExceptionProtectedMessage* message);
3737
static kern_return_t FIRCLSMachExceptionDispatchMessage(FIRCLSMachExceptionReadContext* context,
38-
MachExceptionMessage* message);
38+
MachExceptionProtectedMessage* message);
3939
static bool FIRCLSMachExceptionReply(FIRCLSMachExceptionReadContext* context,
40-
MachExceptionMessage* message,
40+
MachExceptionProtectedMessage* message,
4141
kern_return_t result);
4242
static bool FIRCLSMachExceptionRegister(FIRCLSMachExceptionReadContext* context);
4343
static bool FIRCLSMachExceptionUnregister(FIRCLSMachExceptionOriginalPorts* originalPorts,
4444
exception_mask_t mask);
4545
static bool FIRCLSMachExceptionRecord(FIRCLSMachExceptionReadContext* context,
46-
MachExceptionMessage* message);
47-
46+
MachExceptionProtectedMessage* message);
47+
static void FIRCLSCrashedThreadLookup(MachExceptionProtectedMessage* message, thread_t* crashedThread);
4848
#pragma mark - Initialization
4949
void FIRCLSMachExceptionInit(FIRCLSMachExceptionReadContext* context) {
5050
if (!FIRCLSUnlinkIfExists(context->path)) {
@@ -166,7 +166,7 @@ static void* FIRCLSMachExceptionServer(void* argument) {
166166
pthread_setname_np("com.google.firebase.crashlytics.MachExceptionServer");
167167

168168
while (1) {
169-
MachExceptionMessage message;
169+
MachExceptionProtectedMessage message;
170170

171171
// read the exception message
172172
if (!FIRCLSMachExceptionReadMessage(context, &message)) {
@@ -188,12 +188,12 @@ static void* FIRCLSMachExceptionServer(void* argument) {
188188
}
189189

190190
static bool FIRCLSMachExceptionReadMessage(FIRCLSMachExceptionReadContext* context,
191-
MachExceptionMessage* message) {
191+
MachExceptionProtectedMessage* message) {
192192
mach_msg_return_t r;
193193

194-
memset(message, 0, sizeof(MachExceptionMessage));
194+
memset(message, 0, sizeof(MachExceptionProtectedMessage));
195195

196-
r = mach_msg(&message->head, MACH_RCV_MSG | MACH_RCV_LARGE, 0, sizeof(MachExceptionMessage),
196+
r = mach_msg(&message->head, MACH_RCV_MSG | MACH_RCV_LARGE, 0, sizeof(MachExceptionProtectedMessage),
197197
context->port, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
198198
if (r != MACH_MSG_SUCCESS) {
199199
FIRCLSSDKLog("Error receiving mach_msg (%d)\n", r);
@@ -206,14 +206,19 @@ static bool FIRCLSMachExceptionReadMessage(FIRCLSMachExceptionReadContext* conte
206206
}
207207

208208
static kern_return_t FIRCLSMachExceptionDispatchMessage(FIRCLSMachExceptionReadContext* context,
209-
MachExceptionMessage* message) {
209+
MachExceptionProtectedMessage* message) {
210210
FIRCLSSDKLog("Mach exception: 0x%x, count: %d, code: 0x%llx 0x%llx\n", message->exception,
211211
message->codeCnt, message->codeCnt > 0 ? message->code[0] : -1,
212212
message->codeCnt > 1 ? message->code[1] : -1);
213213

214214
// This will happen if a child process raises an exception, as the exception ports are
215215
// inherited.
216-
if (message->task.name != mach_task_self()) {
216+
mach_port_t actual_port;
217+
kern_return_t kr;
218+
task_id_token_t token = message->task_id.name;
219+
kr = task_identity_token_get_task_port(token, TASK_FLAVOR_CONTROL, &actual_port);
220+
221+
if (kr || actual_port != mach_task_self()) {
217222
FIRCLSSDKLog("Mach exception task mis-match, returning failure\n");
218223
return KERN_FAILURE;
219224
}
@@ -240,7 +245,7 @@ static kern_return_t FIRCLSMachExceptionDispatchMessage(FIRCLSMachExceptionReadC
240245
}
241246

242247
static bool FIRCLSMachExceptionReply(FIRCLSMachExceptionReadContext* context,
243-
MachExceptionMessage* message,
248+
MachExceptionProtectedMessage* message,
244249
kern_return_t result) {
245250
MachExceptionReply reply;
246251
mach_msg_return_t r;
@@ -296,7 +301,7 @@ static bool FIRCLSMachExceptionRegister(FIRCLSMachExceptionReadContext* context)
296301

297302
// ORing with MACH_EXCEPTION_CODES will produce 64-bit exception data
298303
kr = task_swap_exception_ports(task, context->mask, context->port,
299-
EXCEPTION_DEFAULT | MACH_EXCEPTION_CODES, THREAD_STATE_NONE,
304+
EXCEPTION_IDENTITY_PROTECTED | MACH_EXCEPTION_CODES, THREAD_STATE_NONE,
300305
context->originalPorts.masks, &context->originalPorts.count,
301306
context->originalPorts.ports, context->originalPorts.behaviors,
302307
context->originalPorts.flavors);
@@ -333,7 +338,7 @@ static bool FIRCLSMachExceptionUnregister(FIRCLSMachExceptionOriginalPorts* orig
333338

334339
// Finally, mark any masks we registered for that do not have an original port as unused.
335340
kr = task_set_exception_ports(mach_task_self(), mask, MACH_PORT_NULL,
336-
EXCEPTION_DEFAULT | MACH_EXCEPTION_CODES, THREAD_STATE_NONE);
341+
EXCEPTION_IDENTITY_PROTECTED | MACH_EXCEPTION_CODES, THREAD_STATE_NONE);
337342
if (kr != KERN_SUCCESS) {
338343
FIRCLSSDKLog("unable to unset unregistered mask: 0x%x", mask);
339344
return false;
@@ -472,7 +477,7 @@ void FIRCLSMachExceptionNameLookup(exception_type_t number,
472477
}
473478

474479
static bool FIRCLSMachExceptionRecord(FIRCLSMachExceptionReadContext* context,
475-
MachExceptionMessage* message) {
480+
MachExceptionProtectedMessage* message) {
476481
if (!context || !message) {
477482
return false;
478483
}
@@ -520,13 +525,53 @@ static bool FIRCLSMachExceptionRecord(FIRCLSMachExceptionReadContext* context,
520525

521526
FIRCLSFileWriteSectionEnd(&file);
522527

523-
FIRCLSHandler(&file, message->thread.name, NULL, true);
528+
thread_t crashedThread;
529+
FIRCLSCrashedThreadLookup(message, &crashedThread);
530+
FIRCLSSDKLog("Crashed threads: %d\n", crashedThread);
531+
FIRCLSHandler(&file, crashedThread, NULL, true);
524532

525533
FIRCLSFileClose(&file);
526534

527535
return true;
528536
}
529537

538+
static void FIRCLSCrashedThreadLookup(MachExceptionProtectedMessage* message, thread_t* crashedThread) {
539+
thread_act_array_t threadList;
540+
mach_msg_type_number_t threadCount;
541+
542+
// last 32 bits include thread id info
543+
MachExceptionProtectedThreadInfo protected_thread_info = *(MachExceptionProtectedThreadInfo *) &message->thread_id;
544+
kern_return_t kr = task_threads(mach_task_self(), &threadList, &threadCount);
545+
546+
if (kr != KERN_SUCCESS) {
547+
FIRCLSSDKLogError("Failed to get threads: %d\n", kr);
548+
return;
549+
}
550+
for (int i = 0; i < threadCount; i++) {
551+
thread_t thread = threadList[i];
552+
553+
thread_basic_info_data_t basicInfo;
554+
thread_identifier_info_data_t identifierInfo;
555+
mach_msg_type_number_t infoCount = THREAD_BASIC_INFO_COUNT;
556+
557+
kr = thread_info(thread, THREAD_IDENTIFIER_INFO, (thread_info_t)&identifierInfo, &infoCount);
558+
559+
if (kr == KERN_SUCCESS) {
560+
FIRCLSSDKLog("Thread %d: Thread port: %d, thread id: %llx\n", i, thread, identifierInfo.thread_id);
561+
562+
if (protected_thread_info.thread_id == identifierInfo.thread_id) {
563+
FIRCLSSDKLog("Find crashed thread: %d\n", thread);
564+
*crashedThread = thread;
565+
}
566+
}
567+
568+
// Note: You must deallocate the send right for each thread port
569+
// to prevent port leaks, as task_threads increments the ref count.
570+
mach_port_deallocate(mach_task_self(), thread);
571+
}
572+
vm_deallocate(mach_task_self(), (vm_address_t)threadList, threadCount * sizeof(thread_t));
573+
}
574+
530575
#else
531576

532577
INJECT_STRIP_SYMBOL(cls_mach_exception)

Crashlytics/Crashlytics/Handlers/FIRCLSMachException.h

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,15 +31,21 @@ typedef struct {
3131
mach_msg_header_t head;
3232
/* start of the kernel processed data */
3333
mach_msg_body_t msgh_body;
34-
mach_msg_port_descriptor_t thread;
35-
mach_msg_port_descriptor_t task;
34+
mach_msg_port_descriptor_t task_id;
35+
mach_msg_port_descriptor_t thread_id;
3636
/* end of the kernel processed data */
3737
NDR_record_t NDR;
3838
exception_type_t exception;
3939
mach_msg_type_number_t codeCnt;
4040
mach_exception_data_type_t code[EXCEPTION_CODE_MAX];
4141
mach_msg_trailer_t trailer;
42-
} MachExceptionMessage;
42+
} MachExceptionProtectedMessage;
43+
44+
typedef struct {
45+
unsigned int pad1;
46+
unsigned int pad2;
47+
uint64_t thread_id;
48+
} MachExceptionProtectedThreadInfo;
4349

4450
typedef struct {
4551
mach_msg_header_t head;

0 commit comments

Comments
 (0)