Skip to content

Commit 356732b

Browse files
committed
make mach behavior configurable
1 parent c7a16af commit 356732b

File tree

8 files changed

+76
-26
lines changed

8 files changed

+76
-26
lines changed

Crashlytics/CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# Unrelased
2-
- [fixed] Conformed to Mach IPC security restrictions. Note: This change would potentially change mach exception types we receive from kernel which might affect issue clustering result. (#15393)
2+
- [fixed] Added ability to conformed to Mach IPC security restrictions. User need to add FirebaseCrashlyticsMachProtectedEnabled=YES to their info.plist to enable this feature. Note: This change would potentially change mach exception types we receive from kernel which might affect issue clustering result. (#15393)
33

44
# 12.4.0
55
- [fixed] Make set development platform APIs to chain on Crashlytics context init promise.

Crashlytics/Crashlytics/Components/FIRCLSContext.m

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@
6565
initData.previouslyCrashedFileRootPath = [fileManager rootPath];
6666
initData.errorsEnabled = [settings errorReportingEnabled];
6767
initData.customExceptionsEnabled = [settings customExceptionsEnabled];
68+
initData.machProtectedEnabled = [settings machProtectedEnabled];
6869
initData.maxCustomExceptions = [settings maxCustomExceptions];
6970
initData.maxErrorLogSize = [settings errorLogBufferSize];
7071
initData.maxLogSize = [settings logBufferSize];
@@ -185,6 +186,12 @@
185186
_firclsContext.readonly->machException.path =
186187
FIRCLSContextAppendToRoot(rootPath, FIRCLSReportMachExceptionFile);
187188

189+
// from settings checkout behavior
190+
_firclsContext.readonly->machException.behavior = EXCEPTION_DEFAULT;
191+
if (initData.machProtectedEnabled) {
192+
_firclsContext.readonly->machException.behavior = EXCEPTION_IDENTITY_PROTECTED;
193+
}
194+
188195
FIRCLSMachExceptionInit(&_firclsContext.readonly->machException);
189196
});
190197
#endif

Crashlytics/Crashlytics/FIRCrashlytics.m

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,11 +146,14 @@ - (instancetype)initWithApp:(FIRApp *)app
146146

147147
_fileManager = [[FIRCLSFileManager alloc] init];
148148
_googleAppID = app.options.googleAppID;
149+
// getting data collection state from info.plist, user defaults etc. disk I/O on main
149150
_dataArbiter = [[FIRCLSDataCollectionArbiter alloc] initWithApp:app withAppInfo:appInfo];
150151

151152
FIRCLSApplicationIdentifierModel *appModel = [[FIRCLSApplicationIdentifierModel alloc] init];
153+
// read settings cache, disk I/O on main
152154
FIRCLSSettings *settings = [[FIRCLSSettings alloc] initWithFileManager:_fileManager
153-
appIDModel:appModel];
155+
appIDModel:appModel
156+
appInfo:appInfo];
154157

155158
FIRCLSOnDemandModel *onDemandModel =
156159
[[FIRCLSOnDemandModel alloc] initWithFIRCLSSettings:settings fileManager:_fileManager];
@@ -200,6 +203,7 @@ - (instancetype)initWithApp:(FIRApp *)app
200203
}
201204

202205
_contextInitPromise =
206+
// setup with context init (binary image, register exception handler)
203207
[[[_reportManager startWithProfiling] then:^id _Nullable(NSNumber *_Nullable value) {
204208
if (![value boolValue]) {
205209
FIRCLSErrorLog(@"Crash reporting could not be initialized");

Crashlytics/Crashlytics/Handlers/FIRCLSMachException.c

Lines changed: 29 additions & 19 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-
MachExceptionProtectedMessage* message);
36+
MachExceptionMessage* message);
3737
static kern_return_t FIRCLSMachExceptionDispatchMessage(FIRCLSMachExceptionReadContext* context,
38-
MachExceptionProtectedMessage* message);
38+
MachExceptionMessage* message);
3939
static bool FIRCLSMachExceptionReply(FIRCLSMachExceptionReadContext* context,
40-
MachExceptionProtectedMessage* message,
40+
MachExceptionMessage* 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-
MachExceptionProtectedMessage* message);
47-
static void FIRCLSCrashedThreadLookup(MachExceptionProtectedMessage* message, thread_t* crashedThread);
46+
MachExceptionMessage* message);
47+
static void FIRCLSCrashedThreadLookup(MachExceptionMessage* 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-
MachExceptionProtectedMessage message;
169+
MachExceptionMessage 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-
MachExceptionProtectedMessage* message) {
191+
MachExceptionMessage* message) {
192192
mach_msg_return_t r;
193193

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

196-
r = mach_msg(&message->head, MACH_RCV_MSG | MACH_RCV_LARGE, 0, sizeof(MachExceptionProtectedMessage),
196+
r = mach_msg(&message->head, MACH_RCV_MSG | MACH_RCV_LARGE, 0, sizeof(MachExceptionMessage),
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,17 +206,22 @@ static bool FIRCLSMachExceptionReadMessage(FIRCLSMachExceptionReadContext* conte
206206
}
207207

208208
static kern_return_t FIRCLSMachExceptionDispatchMessage(FIRCLSMachExceptionReadContext* context,
209-
MachExceptionProtectedMessage* message) {
209+
MachExceptionMessage* 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.
216216
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);
217+
kern_return_t kr = KERN_SUCCESS;
218+
if (context->behavior == EXCEPTION_DEFAULT){
219+
actual_port = message->payload_2.name;
220+
} else {
221+
// EXCEPTION_IDENTITY_PROTECTED
222+
task_id_token_t token = message->payload_1.name;
223+
kr = task_identity_token_get_task_port(token, TASK_FLAVOR_CONTROL, &actual_port);
224+
}
220225

221226
if (kr || actual_port != mach_task_self()) {
222227
FIRCLSSDKLog("Mach exception task mis-match, returning failure\n");
@@ -245,7 +250,7 @@ static kern_return_t FIRCLSMachExceptionDispatchMessage(FIRCLSMachExceptionReadC
245250
}
246251

247252
static bool FIRCLSMachExceptionReply(FIRCLSMachExceptionReadContext* context,
248-
MachExceptionProtectedMessage* message,
253+
MachExceptionMessage* message,
249254
kern_return_t result) {
250255
MachExceptionReply reply;
251256
mach_msg_return_t r;
@@ -301,7 +306,7 @@ static bool FIRCLSMachExceptionRegister(FIRCLSMachExceptionReadContext* context)
301306

302307
// ORing with MACH_EXCEPTION_CODES will produce 64-bit exception data
303308
kr = task_swap_exception_ports(task, context->mask, context->port,
304-
EXCEPTION_IDENTITY_PROTECTED | MACH_EXCEPTION_CODES, THREAD_STATE_NONE,
309+
context->behavior | MACH_EXCEPTION_CODES, THREAD_STATE_NONE,
305310
context->originalPorts.masks, &context->originalPorts.count,
306311
context->originalPorts.ports, context->originalPorts.behaviors,
307312
context->originalPorts.flavors);
@@ -477,7 +482,7 @@ void FIRCLSMachExceptionNameLookup(exception_type_t number,
477482
}
478483

479484
static bool FIRCLSMachExceptionRecord(FIRCLSMachExceptionReadContext* context,
480-
MachExceptionProtectedMessage* message) {
485+
MachExceptionMessage* message) {
481486
if (!context || !message) {
482487
return false;
483488
}
@@ -526,7 +531,12 @@ static bool FIRCLSMachExceptionRecord(FIRCLSMachExceptionReadContext* context,
526531
FIRCLSFileWriteSectionEnd(&file);
527532

528533
thread_t crashedThread;
529-
FIRCLSCrashedThreadLookup(message, &crashedThread);
534+
if (context->behavior == EXCEPTION_DEFAULT) {
535+
crashedThread = message->payload_1.name;
536+
} else {
537+
// EXCEPTION_IDENTITY_PROTECTED
538+
FIRCLSCrashedThreadLookup(message, &crashedThread);
539+
}
530540
FIRCLSSDKLog("Crashed threads: %d\n", crashedThread);
531541
FIRCLSHandler(&file, crashedThread, NULL, true);
532542

@@ -535,12 +545,12 @@ static bool FIRCLSMachExceptionRecord(FIRCLSMachExceptionReadContext* context,
535545
return true;
536546
}
537547

538-
static void FIRCLSCrashedThreadLookup(MachExceptionProtectedMessage* message, thread_t* crashedThread) {
548+
static void FIRCLSCrashedThreadLookup(MachExceptionMessage* message, thread_t* crashedThread) {
539549
thread_act_array_t threadList;
540550
mach_msg_type_number_t threadCount;
541551

542552
// last 64 bits include thread id info
543-
MachExceptionProtectedThreadInfo protected_thread_info = *(MachExceptionProtectedThreadInfo *) &message->thread_id;
553+
MachExceptionProtectedThreadInfo protected_thread_info = *(MachExceptionProtectedThreadInfo *) &message->payload_2;
544554
kern_return_t kr = task_threads(mach_task_self(), &threadList, &threadCount);
545555

546556
if (kr != KERN_SUCCESS) {

Crashlytics/Crashlytics/Handlers/FIRCLSMachException.h

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,19 +27,25 @@
2727

2828
#pragma mark Structures
2929
#pragma pack(push, 4)
30+
// When set Mach port with default behavior:
31+
// payload_1 including thread port
32+
// payload_2 including task port
33+
// When set Mach port with identity protected behavior:
34+
// payload_1 including task_id_token
35+
// payload_2 including thread_id
3036
typedef struct {
3137
mach_msg_header_t head;
3238
/* start of the kernel processed data */
3339
mach_msg_body_t msgh_body;
34-
mach_msg_port_descriptor_t task_id;
35-
mach_msg_port_descriptor_t thread_id;
40+
mach_msg_port_descriptor_t payload_1;
41+
mach_msg_port_descriptor_t payload_2;
3642
/* end of the kernel processed data */
3743
NDR_record_t NDR;
3844
exception_type_t exception;
3945
mach_msg_type_number_t codeCnt;
4046
mach_exception_data_type_t code[EXCEPTION_CODE_MAX];
4147
mach_msg_trailer_t trailer;
42-
} MachExceptionProtectedMessage;
48+
} MachExceptionMessage;
4349

4450
typedef struct {
4551
uint64_t pad1;
@@ -68,6 +74,7 @@ typedef struct {
6874

6975
exception_mask_t mask;
7076
FIRCLSMachExceptionOriginalPorts originalPorts;
77+
exception_behavior_t behavior;
7178
} FIRCLSMachExceptionReadContext;
7279

7380
#pragma mark - API

Crashlytics/Crashlytics/Helpers/FIRCLSContextInitData.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ NS_ASSUME_NONNULL_BEGIN
2828
@property(nonatomic, copy) NSString* betaToken;
2929
@property(nonatomic) BOOL errorsEnabled;
3030
@property(nonatomic) BOOL customExceptionsEnabled;
31+
@property(nonatomic) BOOL machProtectedEnabled;
3132
@property(nonatomic) uint32_t maxCustomExceptions;
3233
@property(nonatomic) uint32_t maxErrorLogSize;
3334
@property(nonatomic) uint32_t maxLogSize;

Crashlytics/Crashlytics/Models/FIRCLSSettings.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ NS_ASSUME_NONNULL_BEGIN
3030
- (instancetype)init NS_UNAVAILABLE;
3131
+ (instancetype)new NS_UNAVAILABLE;
3232
- (instancetype)initWithFileManager:(FIRCLSFileManager *)fileManager
33-
appIDModel:(FIRCLSApplicationIdentifierModel *)appIDModel;
33+
appIDModel:(FIRCLSApplicationIdentifierModel *)appIDModel
34+
appInfo:(NSDictionary *)appInfo;
3435

3536
/**
3637
* Recreates the settings dictionary by re-reading the settings file from persistent storage. This
@@ -78,6 +79,12 @@ NS_ASSUME_NONNULL_BEGIN
7879
*/
7980
@property(nonatomic, readonly) BOOL customExceptionsEnabled;
8081

82+
/**
83+
* When this is true, Crashlytics will use EXCEPTION_IDENTITY_PROTECTED
84+
* for mach exception handler instead of EXCEPTION_DEFAULT for default
85+
*/
86+
@property(nonatomic) BOOL machProtectedEnabled;
87+
8188
/**
8289
* When this is true, Crashlytics will collect data from MetricKit
8390
*/

Crashlytics/Crashlytics/Models/FIRCLSSettings.m

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@
3030
NSString *const GoogleAppIDKey = @"google_app_id";
3131
NSString *const BuildInstanceID = @"build_instance_id";
3232
NSString *const AppVersion = @"app_version";
33+
NSString *const FirebaseCrashlyticsMachProtectedEnabledKey =
34+
@"FirebaseCrashlyticsMachProtectedEnabled";
3335

3436
@interface FIRCLSSettings ()
3537

@@ -47,21 +49,33 @@ @interface FIRCLSSettings ()
4749
@implementation FIRCLSSettings
4850

4951
- (instancetype)initWithFileManager:(FIRCLSFileManager *)fileManager
50-
appIDModel:(FIRCLSApplicationIdentifierModel *)appIDModel {
52+
appIDModel:(FIRCLSApplicationIdentifierModel *)appIDModel
53+
appInfo:(NSDictionary *)appInfo {
5154
return
5255
[self initWithFileManager:fileManager
5356
appIDModel:appIDModel
57+
appInfo:(NSDictionary *)appInfo
5458
deletionQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0)];
5559
}
5660

5761
- (instancetype)initWithFileManager:(FIRCLSFileManager *)fileManager
5862
appIDModel:(FIRCLSApplicationIdentifierModel *)appIDModel
63+
appInfo:(NSDictionary *)appInfo
5964
deletionQueue:(dispatch_queue_t)deletionQueue {
6065
self = [super init];
6166
if (!self) {
6267
return nil;
6368
}
6469

70+
// config the mach exception message receiving behavior
71+
self.machProtectedEnabled = false;
72+
id crashlyticsMachProtectedEnabled =
73+
[appInfo objectForKey:FirebaseCrashlyticsMachProtectedEnabledKey];
74+
if ([crashlyticsMachProtectedEnabled isKindOfClass:[NSString class]] ||
75+
[crashlyticsMachProtectedEnabled isKindOfClass:[NSNumber class]]) {
76+
self.machProtectedEnabled = [crashlyticsMachProtectedEnabled boolValue];
77+
}
78+
6579
_fileManager = fileManager;
6680
_appIDModel = appIDModel;
6781

0 commit comments

Comments
 (0)