Skip to content

Commit 5125d5c

Browse files
authored
[Crashlytics] Mach IPC identity protected address backwards compatibility (#15725)
1 parent 88a4ac0 commit 5125d5c

File tree

3 files changed

+105
-47
lines changed

3 files changed

+105
-47
lines changed

Crashlytics/Crashlytics/Components/FIRCLSContext.m

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,13 @@
185185
_firclsContext.readonly->machException.path =
186186
FIRCLSContextAppendToRoot(rootPath, FIRCLSReportMachExceptionFile);
187187

188+
// MacOS12 below does not support identity protected behavior
189+
// check releases here: https://opensource.apple.com/releases/
190+
// TODO: remove EXCEPTION_DEFAULT support when we bump min MacOS support to 12+
191+
_firclsContext.readonly->machException.behavior = EXCEPTION_DEFAULT;
192+
if (@available(macOS 12, *)) {
193+
_firclsContext.readonly->machException.behavior = EXCEPTION_IDENTITY_PROTECTED;
194+
}
188195
FIRCLSMachExceptionInit(&_firclsContext.readonly->machException);
189196
});
190197
#endif

Crashlytics/Crashlytics/Handlers/FIRCLSMachException.c

Lines changed: 78 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -33,18 +33,19 @@
3333
static void* FIRCLSMachExceptionServer(void* argument);
3434
static bool FIRCLSMachExceptionThreadStart(FIRCLSMachExceptionReadContext* context);
3535
static bool FIRCLSMachExceptionReadMessage(FIRCLSMachExceptionReadContext* context,
36-
MachExceptionProtectedMessage* message);
36+
union MachExceptionMessage* message);
3737
static kern_return_t FIRCLSMachExceptionDispatchMessage(FIRCLSMachExceptionReadContext* context,
38-
MachExceptionProtectedMessage* message);
38+
union MachExceptionMessage* message);
3939
static bool FIRCLSMachExceptionReply(FIRCLSMachExceptionReadContext* context,
40-
MachExceptionProtectedMessage* message,
40+
union MachExceptionMessage* message,
4141
kern_return_t result);
4242
static bool FIRCLSMachExceptionRegister(FIRCLSMachExceptionReadContext* context);
4343
static bool FIRCLSMachExceptionUnregister(FIRCLSMachExceptionOriginalPorts* originalPorts,
44-
exception_mask_t mask);
44+
exception_mask_t mask,
45+
exception_behavior_t behavior);
4546
static bool FIRCLSMachExceptionRecord(FIRCLSMachExceptionReadContext* context,
46-
MachExceptionProtectedMessage* message);
47-
static void FIRCLSCrashedThreadLookup(MachExceptionProtectedMessage* message, thread_t* crashedThread);
47+
union MachExceptionMessage* message);
48+
static void FIRCLSCrashedThreadLookup(union MachExceptionMessage* message, thread_t* crashedThread);
4849
#pragma mark - Initialization
4950
void FIRCLSMachExceptionInit(FIRCLSMachExceptionReadContext* context) {
5051
if (!FIRCLSUnlinkIfExists(context->path)) {
@@ -58,7 +59,7 @@ void FIRCLSMachExceptionInit(FIRCLSMachExceptionReadContext* context) {
5859

5960
if (!FIRCLSMachExceptionThreadStart(context)) {
6061
FIRCLSSDKLog("Unable to start thread\n");
61-
FIRCLSMachExceptionUnregister(&context->originalPorts, context->mask);
62+
FIRCLSMachExceptionUnregister(&context->originalPorts, context->mask, context->behavior);
6263
}
6364
}
6465

@@ -166,7 +167,7 @@ static void* FIRCLSMachExceptionServer(void* argument) {
166167
pthread_setname_np("com.google.firebase.crashlytics.MachExceptionServer");
167168

168169
while (1) {
169-
MachExceptionProtectedMessage message;
170+
union MachExceptionMessage message;
170171

171172
// read the exception message
172173
if (!FIRCLSMachExceptionReadMessage(context, &message)) {
@@ -188,13 +189,15 @@ static void* FIRCLSMachExceptionServer(void* argument) {
188189
}
189190

190191
static bool FIRCLSMachExceptionReadMessage(FIRCLSMachExceptionReadContext* context,
191-
MachExceptionProtectedMessage* message) {
192+
union MachExceptionMessage* message) {
192193
mach_msg_return_t r;
193194

194-
memset(message, 0, sizeof(MachExceptionProtectedMessage));
195+
memset(message, 0, sizeof(union MachExceptionMessage));
195196

196-
r = mach_msg(&message->head, MACH_RCV_MSG | MACH_RCV_LARGE, 0, sizeof(MachExceptionProtectedMessage),
197+
// no need if condition here since head structure for union MachExceptionMessage is the same.
198+
r = mach_msg(&message->default_message.head, MACH_RCV_MSG | MACH_RCV_LARGE, 0, sizeof(union MachExceptionMessage),
197199
context->port, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
200+
198201
if (r != MACH_MSG_SUCCESS) {
199202
FIRCLSSDKLog("Error receiving mach_msg (%d)\n", r);
200203
return false;
@@ -206,33 +209,43 @@ static bool FIRCLSMachExceptionReadMessage(FIRCLSMachExceptionReadContext* conte
206209
}
207210

208211
static kern_return_t FIRCLSMachExceptionDispatchMessage(FIRCLSMachExceptionReadContext* context,
209-
MachExceptionProtectedMessage* message) {
210-
FIRCLSSDKLog("Mach exception: 0x%x, count: %d, code: 0x%llx 0x%llx\n", message->exception,
211-
message->codeCnt, message->codeCnt > 0 ? message->code[0] : -1,
212-
message->codeCnt > 1 ? message->code[1] : -1);
213-
214-
// This will happen if a child process raises an exception, as the exception ports are
215-
// inherited.
216-
mach_port_t actual_port;
212+
union MachExceptionMessage* message) {
217213
kern_return_t kr;
218-
task_id_token_t token = message->task_id_token_t.name;
219-
kr = task_identity_token_get_task_port(token, TASK_FLAVOR_CONTROL, &actual_port);
220214

221-
if (kr != KERN_SUCCESS) {
222-
FIRCLSSDKLog("Could not find task from task id token. returning failure\n");
223-
return KERN_FAILURE;
224-
}
215+
if (context->behavior == EXCEPTION_DEFAULT) {
216+
FIRCLSSDKLog("Mach exception: 0x%x, count: %d, code: 0x%llx 0x%llx\n", message->default_message.exception,
217+
message->default_message.codeCnt, message->default_message.codeCnt > 0 ? message->default_message.code[0] : -1,
218+
message->default_message.codeCnt > 1 ? message->default_message.code[1] : -1);
219+
if(message->default_message.task.name != mach_task_self()) {
220+
FIRCLSSDKLog("Mach exception task mis-match, returning failure\n");
221+
return KERN_FAILURE;
222+
}
223+
} else {
224+
FIRCLSSDKLog("Mach exception: 0x%x, count: %d, code: 0x%llx 0x%llx\n", message->protected_message.exception,
225+
message->protected_message.codeCnt, message->protected_message.codeCnt > 0 ? message->protected_message.code[0] : -1,
226+
message->protected_message.codeCnt > 1 ? message->protected_message.code[1] : -1);
225227

226-
const bool is_mismatch = (actual_port != mach_task_self());
227-
mach_port_deallocate(mach_task_self(), actual_port);
228+
// This will happen if a child process raises an exception, as the exception ports are
229+
// inherited.
230+
mach_port_t actual_port;
231+
task_id_token_t token = message->protected_message.task_id_token_t.name;
232+
kr = task_identity_token_get_task_port(token, TASK_FLAVOR_CONTROL, &actual_port);
228233

229-
if (is_mismatch) {
230-
FIRCLSSDKLog("Mach exception task mis-match, returning failure\n");
231-
return KERN_FAILURE;
234+
if (kr != KERN_SUCCESS) {
235+
FIRCLSSDKLog("Could not find task from task id token. returning failure\n");
236+
return KERN_FAILURE;
237+
}
238+
const bool is_mismatch = (actual_port != mach_task_self());
239+
mach_port_deallocate(mach_task_self(), actual_port);
240+
241+
if (is_mismatch) {
242+
FIRCLSSDKLog("Mach exception task mis-match, returning failure\n");
243+
return KERN_FAILURE;
244+
}
232245
}
233246

234247
FIRCLSSDKLog("Unregistering handler\n");
235-
if (!FIRCLSMachExceptionUnregister(&context->originalPorts, context->mask)) {
248+
if (!FIRCLSMachExceptionUnregister(&context->originalPorts, context->mask, context->behavior)) {
236249
FIRCLSSDKLog("Failed to unregister\n");
237250
return KERN_FAILURE;
238251
}
@@ -253,17 +266,17 @@ static kern_return_t FIRCLSMachExceptionDispatchMessage(FIRCLSMachExceptionReadC
253266
}
254267

255268
static bool FIRCLSMachExceptionReply(FIRCLSMachExceptionReadContext* context,
256-
MachExceptionProtectedMessage* message,
269+
union MachExceptionMessage* message,
257270
kern_return_t result) {
258271
MachExceptionReply reply;
259272
mach_msg_return_t r;
260273

261274
// prepare the reply
262-
reply.head.msgh_bits = MACH_MSGH_BITS(MACH_MSGH_BITS_REMOTE(message->head.msgh_bits), 0);
263-
reply.head.msgh_remote_port = message->head.msgh_remote_port;
275+
reply.head.msgh_bits = MACH_MSGH_BITS(MACH_MSGH_BITS_REMOTE(message->default_message.head.msgh_bits), 0);
276+
reply.head.msgh_remote_port = message->default_message.head.msgh_remote_port;
264277
reply.head.msgh_size = (mach_msg_size_t)sizeof(MachExceptionReply);
265278
reply.head.msgh_local_port = MACH_PORT_NULL;
266-
reply.head.msgh_id = message->head.msgh_id + 100;
279+
reply.head.msgh_id = message->default_message.head.msgh_id + 100;
267280

268281
reply.NDR = NDR_record;
269282

@@ -309,7 +322,7 @@ static bool FIRCLSMachExceptionRegister(FIRCLSMachExceptionReadContext* context)
309322

310323
// ORing with MACH_EXCEPTION_CODES will produce 64-bit exception data
311324
kr = task_swap_exception_ports(task, context->mask, context->port,
312-
EXCEPTION_IDENTITY_PROTECTED | MACH_EXCEPTION_CODES, THREAD_STATE_NONE,
325+
context->behavior | MACH_EXCEPTION_CODES, THREAD_STATE_NONE,
313326
context->originalPorts.masks, &context->originalPorts.count,
314327
context->originalPorts.ports, context->originalPorts.behaviors,
315328
context->originalPorts.flavors);
@@ -328,7 +341,8 @@ static bool FIRCLSMachExceptionRegister(FIRCLSMachExceptionReadContext* context)
328341
}
329342

330343
static bool FIRCLSMachExceptionUnregister(FIRCLSMachExceptionOriginalPorts* originalPorts,
331-
exception_mask_t mask) {
344+
exception_mask_t mask,
345+
exception_behavior_t behavior) {
332346
kern_return_t kr;
333347

334348
// Re-register all the old ports.
@@ -346,7 +360,7 @@ static bool FIRCLSMachExceptionUnregister(FIRCLSMachExceptionOriginalPorts* orig
346360

347361
// Finally, mark any masks we registered for that do not have an original port as unused.
348362
kr = task_set_exception_ports(mach_task_self(), mask, MACH_PORT_NULL,
349-
EXCEPTION_IDENTITY_PROTECTED | MACH_EXCEPTION_CODES, THREAD_STATE_NONE);
363+
behavior | MACH_EXCEPTION_CODES, THREAD_STATE_NONE);
350364
if (kr != KERN_SUCCESS) {
351365
FIRCLSSDKLog("unable to unset unregistered mask: 0x%x", mask);
352366
return false;
@@ -485,7 +499,7 @@ void FIRCLSMachExceptionNameLookup(exception_type_t number,
485499
}
486500

487501
static bool FIRCLSMachExceptionRecord(FIRCLSMachExceptionReadContext* context,
488-
MachExceptionProtectedMessage* message) {
502+
union MachExceptionMessage* message) {
489503
if (!context || !message) {
490504
return false;
491505
}
@@ -507,21 +521,34 @@ static bool FIRCLSMachExceptionRecord(FIRCLSMachExceptionReadContext* context,
507521

508522
FIRCLSFileWriteHashStart(&file);
509523

510-
FIRCLSFileWriteHashEntryUint64(&file, "exception", message->exception);
524+
exception_type_t exception;
525+
mach_msg_type_number_t codeCnt;
526+
mach_exception_data_type_t* code;
527+
528+
if (context->behavior == EXCEPTION_DEFAULT) {
529+
exception = message->default_message.exception;
530+
codeCnt = message->default_message.codeCnt;
531+
code = message->default_message.code;
532+
} else {
533+
exception = message->protected_message.exception;
534+
codeCnt = message->protected_message.codeCnt;
535+
code = message->protected_message.code;
536+
}
537+
538+
FIRCLSFileWriteHashEntryUint64(&file, "exception", exception);
511539

512540
// record the codes
513541
FIRCLSFileWriteHashKey(&file, "codes");
514542
FIRCLSFileWriteArrayStart(&file);
515-
for (mach_msg_type_number_t i = 0; i < message->codeCnt; ++i) {
516-
FIRCLSFileWriteArrayEntryUint64(&file, message->code[i]);
543+
for (mach_msg_type_number_t i = 0; i < codeCnt; ++i) {
544+
FIRCLSFileWriteArrayEntryUint64(&file, code[i]);
517545
}
518546
FIRCLSFileWriteArrayEnd(&file);
519547

520548
const char* name = NULL;
521549
const char* codeName = NULL;
522550

523-
FIRCLSMachExceptionNameLookup(message->exception, message->codeCnt > 0 ? message->code[0] : 0,
524-
&name, &codeName);
551+
FIRCLSMachExceptionNameLookup(exception, codeCnt > 0 ? code[0] : 0, &name, &codeName);
525552

526553
FIRCLSFileWriteHashEntryString(&file, "name", name);
527554
FIRCLSFileWriteHashEntryString(&file, "code_name", codeName);
@@ -534,7 +561,11 @@ static bool FIRCLSMachExceptionRecord(FIRCLSMachExceptionReadContext* context,
534561
FIRCLSFileWriteSectionEnd(&file);
535562

536563
thread_t crashedThread = THREAD_NULL;
537-
FIRCLSCrashedThreadLookup(message, &crashedThread);
564+
if (context->behavior == EXCEPTION_DEFAULT) {
565+
crashedThread = message->default_message.thread.name;
566+
} else {
567+
FIRCLSCrashedThreadLookup(message, &crashedThread);
568+
}
538569
FIRCLSSDKLog("Crashed threads: %d\n", crashedThread);
539570
FIRCLSHandler(&file, crashedThread, NULL, true);
540571
if (crashedThread != THREAD_NULL) {
@@ -545,7 +576,7 @@ static bool FIRCLSMachExceptionRecord(FIRCLSMachExceptionReadContext* context,
545576
return true;
546577
}
547578

548-
static void FIRCLSCrashedThreadLookup(MachExceptionProtectedMessage* message, thread_t* crashedThread) {
579+
static void FIRCLSCrashedThreadLookup(union MachExceptionMessage* message, thread_t* crashedThread) {
549580
thread_act_array_t threadList;
550581
mach_msg_type_number_t threadCount;
551582

@@ -564,7 +595,7 @@ static void FIRCLSCrashedThreadLookup(MachExceptionProtectedMessage* message, th
564595

565596
if (kr == KERN_SUCCESS) {
566597
FIRCLSSDKLog("Thread %d: Thread port: %d, thread id: %llx\n", i, threadList[i], identifierInfo.thread_id);
567-
if (message->thread_id == identifierInfo.thread_id) {
598+
if (message->protected_message.thread_id == identifierInfo.thread_id) {
568599
FIRCLSSDKLog("Find crashed thread: %d\n", threadList[i]);
569600
*crashedThread = threadList[i];
570601
break;

Crashlytics/Crashlytics/Handlers/FIRCLSMachException.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,25 @@ typedef struct {
4343
mach_msg_trailer_t trailer;
4444
} MachExceptionProtectedMessage;
4545

46+
typedef struct {
47+
mach_msg_header_t head;
48+
/* start of the kernel processed data */
49+
mach_msg_body_t msgh_body;
50+
mach_msg_port_descriptor_t thread;
51+
mach_msg_port_descriptor_t task;
52+
/* end of the kernel processed data */
53+
NDR_record_t NDR;
54+
exception_type_t exception;
55+
mach_msg_type_number_t codeCnt;
56+
mach_exception_data_type_t code[EXCEPTION_CODE_MAX];
57+
mach_msg_trailer_t trailer;
58+
} MachExceptionDefaultMessage;
59+
60+
union MachExceptionMessage {
61+
MachExceptionProtectedMessage protected_message;
62+
MachExceptionDefaultMessage default_message;
63+
};
64+
4665
typedef struct {
4766
mach_msg_header_t head;
4867
NDR_record_t NDR;
@@ -65,6 +84,7 @@ typedef struct {
6584

6685
exception_mask_t mask;
6786
FIRCLSMachExceptionOriginalPorts originalPorts;
87+
exception_behavior_t behavior;
6888
} FIRCLSMachExceptionReadContext;
6989

7090
#pragma mark - API

0 commit comments

Comments
 (0)