From 78ee41065513b2405c2081b029bf0c77c1f6f077 Mon Sep 17 00:00:00 2001 From: Matt White <436037+mlw@users.noreply.github.com> Date: Thu, 5 Sep 2024 17:05:57 -0400 Subject: [PATCH 1/3] Use runtime platform binary check for exec evals --- Source/santad/SNTPolicyProcessor.h | 6 --- Source/santad/SNTPolicyProcessor.mm | 70 +++++++++++++++++------------ 2 files changed, 41 insertions(+), 35 deletions(-) diff --git a/Source/santad/SNTPolicyProcessor.h b/Source/santad/SNTPolicyProcessor.h index 56d221952..d6032ee5f 100644 --- a/Source/santad/SNTPolicyProcessor.h +++ b/Source/santad/SNTPolicyProcessor.h @@ -45,12 +45,6 @@ /// only guaranteed for the duration of the call to the block. Do not perform /// any async processing without extending their lifetimes. /// -- (nonnull SNTCachedDecision *)decisionForFileInfo:(nonnull SNTFileInfo *)fileInfo - targetProcess:(nonnull const es_process_t *)targetProc - entitlementsFilterCallback: - (NSDictionary *_Nullable (^_Nonnull)( - const char *_Nullable teamID, - NSDictionary *_Nullable entitlements))entitlementsFilterCallback; - (nonnull SNTCachedDecision *)decisionForFileInfo:(nonnull SNTFileInfo *)fileInfo targetProcess:(nonnull const es_process_t *)targetProc preCodesignCheckCallback:(void (^_Nullable)(void))preCodesignCheckCallback diff --git a/Source/santad/SNTPolicyProcessor.mm b/Source/santad/SNTPolicyProcessor.mm index 1041ef82c..19eac8f09 100644 --- a/Source/santad/SNTPolicyProcessor.mm +++ b/Source/santad/SNTPolicyProcessor.mm @@ -30,6 +30,12 @@ #import "Source/santad/DataLayer/SNTRuleTable.h" #include "absl/container/flat_hash_map.h" +enum class PlatformBinaryState { + kRuntimeTrue = 0, + kRuntimeFalse, + kStaticCheck, +}; + @interface SNTPolicyProcessor () @property SNTRuleTable *ruleTable; @property SNTConfigurator *configurator; @@ -130,7 +136,8 @@ - (BOOL)decision:(SNTCachedDecision *)cd static void UpdateCachedDecisionSigningInfo( SNTCachedDecision *cd, MOLCodesignChecker *csInfo, - NSDictionary *_Nullable (^entitlementsFilterCallback)(NSDictionary *_Nullable entitlements)) { + NSDictionary *_Nullable (^entitlementsFilterCallback)(NSDictionary *_Nullable entitlements), + PlatformBinaryState platformBinaryState) { cd.certSHA256 = csInfo.leafCertificate.SHA256; cd.certCommonName = csInfo.leafCertificate.commonName; cd.certChain = csInfo.certificates; @@ -144,8 +151,21 @@ static void UpdateCachedDecisionSigningInfo( cd.signingID = FormatSigningID(csInfo); } - // Ensure that if no teamID exists that the signing info confirms it is a - // platform binary. If not, remove the signingID. + // Ensure that if no teamID exists but a signingID does exist, that the binary + // is a platform binary. If not, remove the signingID. + if (!cd.teamID && cd.signingID) { + switch (platformBinaryState) { + case PlatformBinaryState::kRuntimeTrue: break; + case PlatformBinaryState::kStaticCheck: + if (!csInfo.platformBinary) { + cd.signingID = nil; + } + break; + case PlatformBinaryState::kRuntimeFalse: OS_FALLTHROUGH; + default: cd.signingID = nil; break; + } + } + if (!cd.teamID && cd.signingID) { if (!csInfo.platformBinary) { cd.signingID = nil; @@ -163,17 +183,18 @@ static void UpdateCachedDecisionSigningInfo( } } -- (nonnull SNTCachedDecision *) - decisionForFileInfo:(nonnull SNTFileInfo *)fileInfo - cdhash:(nullable NSString *)cdhash - fileSHA256:(nullable NSString *)fileSHA256 - certificateSHA256:(nullable NSString *)certificateSHA256 - teamID:(nullable NSString *)teamID - signingID:(nullable NSString *)signingID - isProdSignedCallback:(BOOL (^_Nonnull)())isProdSignedCallback - entitlementsFilterCallback:(NSDictionary *_Nullable (^_Nullable)( - NSDictionary *_Nullable entitlements))entitlementsFilterCallback - preCodesignCheckCallback:(void (^_Nullable)(void))preCodesignCheckCallback { +- (nonnull SNTCachedDecision *)decisionForFileInfo:(nonnull SNTFileInfo *)fileInfo + cdhash:(nullable NSString *)cdhash + fileSHA256:(nullable NSString *)fileSHA256 + certificateSHA256:(nullable NSString *)certificateSHA256 + teamID:(nullable NSString *)teamID + signingID:(nullable NSString *)signingID + isProdSignedCallback:(BOOL (^_Nonnull)())isProdSignedCallback + entitlementsFilterCallback: + (NSDictionary *_Nullable (^_Nullable)( + NSDictionary *_Nullable entitlements))entitlementsFilterCallback + preCodesignCheckCallback:(void (^_Nullable)(void))preCodesignCheckCallback + platformBinaryState:(PlatformBinaryState)platformBinaryState { // Check the hash before allocating a SNTCachedDecision. NSString *fileHash = fileSHA256 ?: fileInfo.SHA256; SNTClientMode mode = [self.configurator clientMode]; @@ -215,7 +236,7 @@ static void UpdateCachedDecisionSigningInfo( cd.signingID = nil; cd.cdhash = nil; } else { - UpdateCachedDecisionSigningInfo(cd, csInfo, entitlementsFilterCallback); + UpdateCachedDecisionSigningInfo(cd, csInfo, entitlementsFilterCallback, platformBinaryState); } } @@ -276,18 +297,6 @@ static void UpdateCachedDecisionSigningInfo( } } -- (nonnull SNTCachedDecision *)decisionForFileInfo:(nonnull SNTFileInfo *)fileInfo - targetProcess:(nonnull const es_process_t *)targetProc - entitlementsFilterCallback: - (NSDictionary *_Nullable (^_Nonnull)( - const char *_Nullable teamID, - NSDictionary *_Nullable entitlements))entitlementsFilterCallback { - return [self decisionForFileInfo:fileInfo - targetProcess:targetProc - preCodesignCheckCallback:nil - entitlementsFilterCallback:entitlementsFilterCallback]; -} - - (nonnull SNTCachedDecision *)decisionForFileInfo:(nonnull SNTFileInfo *)fileInfo targetProcess:(nonnull const es_process_t *)targetProc preCodesignCheckCallback:(void (^_Nullable)(void))preCodesignCheckCallback @@ -344,7 +353,9 @@ - (nonnull SNTCachedDecision *)decisionForFileInfo:(nonnull SNTFileInfo *)fileIn entitlementsFilterCallback:^NSDictionary *(NSDictionary *entitlements) { return entitlementsFilterCallback(entitlementsFilterTeamID, entitlements); } - preCodesignCheckCallback:preCodesignCheckCallback]; + preCodesignCheckCallback:preCodesignCheckCallback + platformBinaryState:(targetProc->is_platform_binary ? PlatformBinaryState::kRuntimeTrue + : PlatformBinaryState::kRuntimeFalse)]; } // Used by `$ santactl fileinfo`. @@ -382,7 +393,8 @@ - (nonnull SNTCachedDecision *)decisionForFilePath:(nonnull NSString *)filePath } } entitlementsFilterCallback:nil - preCodesignCheckCallback:nil]; + preCodesignCheckCallback:nil + platformBinaryState:PlatformBinaryState::kStaticCheck]; } /// From 4185b5dd39405aff9e81802844b5ad0cceee963a Mon Sep 17 00:00:00 2001 From: Matt White <436037+mlw@users.noreply.github.com> Date: Fri, 6 Sep 2024 15:48:48 -0400 Subject: [PATCH 2/3] PR Feedback --- Source/santad/SNTPolicyProcessor.mm | 49 +++++++++++++---------------- 1 file changed, 21 insertions(+), 28 deletions(-) diff --git a/Source/santad/SNTPolicyProcessor.mm b/Source/santad/SNTPolicyProcessor.mm index 19eac8f09..ee9fd56f4 100644 --- a/Source/santad/SNTPolicyProcessor.mm +++ b/Source/santad/SNTPolicyProcessor.mm @@ -135,9 +135,8 @@ - (BOOL)decision:(SNTCachedDecision *)cd } static void UpdateCachedDecisionSigningInfo( - SNTCachedDecision *cd, MOLCodesignChecker *csInfo, - NSDictionary *_Nullable (^entitlementsFilterCallback)(NSDictionary *_Nullable entitlements), - PlatformBinaryState platformBinaryState) { + SNTCachedDecision *cd, MOLCodesignChecker *csInfo, PlatformBinaryState platformBinaryState, + NSDictionary *_Nullable (^entitlementsFilterCallback)(NSDictionary *_Nullable entitlements)) { cd.certSHA256 = csInfo.leafCertificate.SHA256; cd.certCommonName = csInfo.leafCertificate.commonName; cd.certChain = csInfo.certificates; @@ -166,12 +165,6 @@ static void UpdateCachedDecisionSigningInfo( } } - if (!cd.teamID && cd.signingID) { - if (!csInfo.platformBinary) { - cd.signingID = nil; - } - } - NSDictionary *entitlements = csInfo.entitlements; if (entitlementsFilterCallback) { @@ -183,18 +176,18 @@ static void UpdateCachedDecisionSigningInfo( } } -- (nonnull SNTCachedDecision *)decisionForFileInfo:(nonnull SNTFileInfo *)fileInfo - cdhash:(nullable NSString *)cdhash - fileSHA256:(nullable NSString *)fileSHA256 - certificateSHA256:(nullable NSString *)certificateSHA256 - teamID:(nullable NSString *)teamID - signingID:(nullable NSString *)signingID - isProdSignedCallback:(BOOL (^_Nonnull)())isProdSignedCallback - entitlementsFilterCallback: - (NSDictionary *_Nullable (^_Nullable)( - NSDictionary *_Nullable entitlements))entitlementsFilterCallback - preCodesignCheckCallback:(void (^_Nullable)(void))preCodesignCheckCallback - platformBinaryState:(PlatformBinaryState)platformBinaryState { +- (nonnull SNTCachedDecision *) + decisionForFileInfo:(nonnull SNTFileInfo *)fileInfo + cdhash:(nullable NSString *)cdhash + fileSHA256:(nullable NSString *)fileSHA256 + certificateSHA256:(nullable NSString *)certificateSHA256 + teamID:(nullable NSString *)teamID + signingID:(nullable NSString *)signingID + platformBinaryState:(PlatformBinaryState)platformBinaryState + isProdSignedCallback:(BOOL (^_Nonnull)())isProdSignedCallback + entitlementsFilterCallback:(NSDictionary *_Nullable (^_Nullable)( + NSDictionary *_Nullable entitlements))entitlementsFilterCallback + preCodesignCheckCallback:(void (^_Nullable)(void))preCodesignCheckCallback { // Check the hash before allocating a SNTCachedDecision. NSString *fileHash = fileSHA256 ?: fileInfo.SHA256; SNTClientMode mode = [self.configurator clientMode]; @@ -236,7 +229,7 @@ - (nonnull SNTCachedDecision *)decisionForFileInfo:(nonnull SNTFileInfo *)fileIn cd.signingID = nil; cd.cdhash = nil; } else { - UpdateCachedDecisionSigningInfo(cd, csInfo, entitlementsFilterCallback, platformBinaryState); + UpdateCachedDecisionSigningInfo(cd, csInfo, platformBinaryState, entitlementsFilterCallback); } } @@ -347,15 +340,15 @@ - (nonnull SNTCachedDecision *)decisionForFileInfo:(nonnull SNTFileInfo *)fileIn certificateSHA256:nil teamID:teamID signingID:signingID - isProdSignedCallback:^BOOL { + platformBinaryState:(targetProc->is_platform_binary + ? PlatformBinaryState::kRuntimeTrue + : PlatformBinaryState::kRuntimeFalse)isProdSignedCallback:^BOOL { return ((targetProc->codesigning_flags & CS_DEV_CODE) == 0); } entitlementsFilterCallback:^NSDictionary *(NSDictionary *entitlements) { return entitlementsFilterCallback(entitlementsFilterTeamID, entitlements); } - preCodesignCheckCallback:preCodesignCheckCallback - platformBinaryState:(targetProc->is_platform_binary ? PlatformBinaryState::kRuntimeTrue - : PlatformBinaryState::kRuntimeFalse)]; + preCodesignCheckCallback:preCodesignCheckCallback]; } // Used by `$ santactl fileinfo`. @@ -380,6 +373,7 @@ - (nonnull SNTCachedDecision *)decisionForFilePath:(nonnull NSString *)filePath certificateSHA256:identifiers.certificateSHA256 teamID:identifiers.teamID signingID:identifiers.signingID + platformBinaryState:PlatformBinaryState::kStaticCheck isProdSignedCallback:^BOOL { if (csInfo) { // Development OID values defined by Apple and used by the Security Framework @@ -393,8 +387,7 @@ - (nonnull SNTCachedDecision *)decisionForFilePath:(nonnull NSString *)filePath } } entitlementsFilterCallback:nil - preCodesignCheckCallback:nil - platformBinaryState:PlatformBinaryState::kStaticCheck]; + preCodesignCheckCallback:nil]; } /// From e29a83fa2d9c9bab38b88ca9d9000459deeca3bc Mon Sep 17 00:00:00 2001 From: Matt White <436037+mlw@users.noreply.github.com> Date: Fri, 6 Sep 2024 21:52:06 -0400 Subject: [PATCH 3/3] Remove parens to mitigate insane clang-formatting --- Source/santad/SNTPolicyProcessor.mm | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Source/santad/SNTPolicyProcessor.mm b/Source/santad/SNTPolicyProcessor.mm index ee9fd56f4..1084586df 100644 --- a/Source/santad/SNTPolicyProcessor.mm +++ b/Source/santad/SNTPolicyProcessor.mm @@ -340,9 +340,9 @@ - (nonnull SNTCachedDecision *)decisionForFileInfo:(nonnull SNTFileInfo *)fileIn certificateSHA256:nil teamID:teamID signingID:signingID - platformBinaryState:(targetProc->is_platform_binary - ? PlatformBinaryState::kRuntimeTrue - : PlatformBinaryState::kRuntimeFalse)isProdSignedCallback:^BOOL { + platformBinaryState:targetProc->is_platform_binary ? PlatformBinaryState::kRuntimeTrue + : PlatformBinaryState::kRuntimeFalse + isProdSignedCallback:^BOOL { return ((targetProc->codesigning_flags & CS_DEV_CODE) == 0); } entitlementsFilterCallback:^NSDictionary *(NSDictionary *entitlements) {