-
Notifications
You must be signed in to change notification settings - Fork 379
Fix a rare crash in TSKSPKIHashCache #348
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
6d73e01
580ce02
3dca5a8
d2b95d3
57195f9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -148,8 +148,22 @@ - (SPKICacheDictionnary *)loadSPKICacheFromFileSystem; | |
|
|
||
| @implementation TSKSPKIHashCache | ||
|
|
||
| /// Blocks to call out to the main thread if necessary | ||
| static BOOL isProtectedDataAvailable(void) | ||
| { | ||
| if (NSThread.isMainThread) { | ||
| return _isProtectedDataAvailable(); | ||
| } else { | ||
| __block BOOL ret = NO; | ||
| dispatch_sync(dispatch_get_main_queue(), ^{ | ||
| ret = _isProtectedDataAvailable(); | ||
| }); | ||
|
|
||
| return ret; | ||
| } | ||
| } | ||
|
|
||
| static BOOL _isProtectedDataAvailable(void) { | ||
| Class uiApplicationClass = objc_getClass("UIApplication"); | ||
| if (uiApplicationClass) { | ||
| SEL sharedApplicationSelector = sel_registerName("sharedApplication"); | ||
|
|
@@ -168,7 +182,7 @@ - (instancetype)initWithIdentifier:(NSString *)uniqueIdentifier | |
| self = [super init]; | ||
| if (self) { | ||
| // Initialize our locks | ||
| _lockQueue = dispatch_queue_create("TSKSPKIHashLock", DISPATCH_QUEUE_CONCURRENT); | ||
| _lockQueue = dispatch_queue_create("TSKSPKIHashLock", DISPATCH_QUEUE_SERIAL); | ||
|
|
||
| // Ensure a non-nil identifier was provided | ||
| NSAssert(uniqueIdentifier, @"TSKSPKIHashCache initializer must be passed a unique identifier"); | ||
|
|
@@ -185,16 +199,21 @@ - (instancetype)initWithIdentifier:(NSString *)uniqueIdentifier | |
| return self; | ||
| } | ||
|
|
||
| - (NSData *)hashSubjectPublicKeyInfoFromCertificate:(SecCertificateRef)certificate | ||
| { | ||
| __block NSData *cachedSubjectPublicKeyInfo; | ||
| - (NSData *)hashSubjectPublicKeyInfoFromCertificate:(SecCertificateRef)certificate { | ||
| __block NSData *hash = nil; | ||
|
|
||
| dispatch_sync(self.lockQueue, ^{ | ||
| hash = [self _hashSubjectPublicKeyInfoFromCertificate:certificate]; | ||
| }); | ||
|
|
||
| return hash; | ||
| } | ||
|
|
||
| - (NSData *)_hashSubjectPublicKeyInfoFromCertificate:(SecCertificateRef)certificate | ||
| { | ||
| // Have we seen this certificate before? Look for the SPKI in the cache | ||
| NSData *certificateData = (__bridge_transfer NSData *)(SecCertificateCopyData(certificate)); | ||
|
|
||
| dispatch_sync(_lockQueue, ^{ | ||
| cachedSubjectPublicKeyInfo = self->_spkiCache[certificateData]; | ||
| }); | ||
| NSData *cachedSubjectPublicKeyInfo = self->_spkiCache[certificateData]; | ||
|
|
||
| if (cachedSubjectPublicKeyInfo) | ||
| { | ||
|
|
@@ -255,35 +274,22 @@ - (NSData *)hashSubjectPublicKeyInfoFromCertificate:(SecCertificateRef)certifica | |
|
|
||
|
|
||
| // Store the hash in our memory cache | ||
| dispatch_barrier_sync(_lockQueue, ^{ | ||
| self->_spkiCache[certificateData] = subjectPublicKeyInfoHash; | ||
| }); | ||
| self->_spkiCache[certificateData] = subjectPublicKeyInfoHash; | ||
|
Comment on lines
-258
to
+277
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
|
||
| // Update the cache on the filesystem | ||
| if (self.spkiCacheFilename.length > 0) { | ||
|
|
||
| __weak typeof(self) weakSelf = self; | ||
| void (^updateCacheBlock)(void) = ^{ | ||
|
|
||
| if (isProtectedDataAvailable()) { | ||
| NSData *serializedSpkiCache = [NSKeyedArchiver archivedDataWithRootObject:weakSelf.spkiCache requiringSecureCoding:YES error:nil]; | ||
| if ([serializedSpkiCache writeToURL:[weakSelf SPKICachePath] atomically:YES] == NO) { | ||
| NSAssert(false, @"Failed to write cache"); | ||
| TSKLog(@"Could not persist SPKI cache to the filesystem"); | ||
| } | ||
| } | ||
| else { | ||
| TSKLog(@"Protected data not available, skipping SPKI cache persistence"); | ||
| } | ||
| }; | ||
|
|
||
| if ([NSThread isMainThread]) { | ||
| updateCacheBlock(); | ||
| } | ||
| else { | ||
| dispatch_async(dispatch_get_main_queue(), updateCacheBlock); | ||
| if (self.spkiCacheFilename.length && isProtectedDataAvailable()) { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This will block to call out to the main queue, but that is our last resort, short of refactoring this method and several others to be totally asynchronous, which would be a massive undertaking. The main queue is a well oiled machine and shouldn't be busy for more than a few ms at any given time, and if it is, the app has much bigger problems than blocking this queue waiting on it |
||
| NSData *serializedSpkiCache = [NSKeyedArchiver archivedDataWithRootObject:self.spkiCache | ||
| requiringSecureCoding:YES | ||
| error:nil]; | ||
| NSURL *cachePath = [self SPKICachePath]; | ||
| if (!cachePath || ![serializedSpkiCache writeToURL:cachePath atomically:YES]) { | ||
| NSAssert(false, @"Failed to write cache"); | ||
| TSKLog(@"Could not persist SPKI cache to the filesystem"); | ||
| } | ||
| } | ||
| else if (self.spkiCacheFilename.length) { | ||
| TSKLog(@"Protected data not available, skipping SPKI cache persistence"); | ||
| } | ||
|
|
||
| return subjectPublicKeyInfoHash; | ||
| } | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
_hashSubjectPublicKeyInfoFromCertificate:is entirely in the lock queue now