Skip to content
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

santad: add critical system binaries #296

Merged
merged 3 commits into from Sep 20, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 4 additions & 4 deletions Podfile.lock
Expand Up @@ -7,11 +7,11 @@ PODS:
- MOLCertificate (1.9)
- MOLCodesignChecker (1.10):
- MOLCertificate (~> 1.8)
- MOLFCMClient (1.7):
- MOLFCMClient (1.8):
- MOLAuthenticatingURLSession (~> 2.4)
- MOLXPCConnection (1.2):
- MOLCodesignChecker (~> 1.9)
- OCMock (3.4.1)
- OCMock (3.4.2)

DEPENDENCIES:
- FMDB
Expand All @@ -37,9 +37,9 @@ SPEC CHECKSUMS:
MOLAuthenticatingURLSession: c238aa1c9a7b1077eb39a6f40204bfe76a7d204e
MOLCertificate: e9e88a396c57032cab847f51a46e20c730cd752a
MOLCodesignChecker: b0d5db9d2f9bd94e0fd093891a5d40e5ad77cbc0
MOLFCMClient: ee45348909351f232e2759c580329072ae7e02d4
MOLFCMClient: 2bfbacd45cc11e1ca3c077e97b80401c4e4a54f1
MOLXPCConnection: c27af5cb1c43b18319698b0e568a8ddc2fc1e306
OCMock: 2cd0716969bab32a2283ff3a46fd26a8c8b4c5e3
OCMock: ebe9ee1dca7fbed0ff9193ac0b3e2d8862ea56f6

PODFILE CHECKSUM: ddca043a7ace9ec600c108621c56d13a50d17236

Expand Down
9 changes: 9 additions & 0 deletions Source/santad/DataLayer/SNTRuleTable.h
Expand Up @@ -17,6 +17,7 @@
#import "SNTCommonEnums.h"
#import "SNTDatabaseTable.h"

@class SNTCachedDecision;
@class SNTRule;
@class SNTNotificationMessage;

Expand Down Expand Up @@ -88,4 +89,12 @@
///
- (void)removeOutdatedTransitiveRules;


///
/// A map of a file hashes to cached decisions. This is used to pre-validate and whitelist
/// certain critical system binaries that are integral to Santa's functionality.
///
@property(readonly, nonatomic)
NSDictionary<NSString *, SNTCachedDecision *> *criticalSystemBinaries;

@end
39 changes: 38 additions & 1 deletion Source/santad/DataLayer/SNTRuleTable.m
Expand Up @@ -17,7 +17,9 @@
#import <MOLCertificate/MOLCertificate.h>
#import <MOLCodesignChecker/MOLCodesignChecker.h>

#import "SNTCachedDecision.h"
#import "SNTConfigurator.h"
#import "SNTFileInfo.h"
#import "SNTLogging.h"
#import "SNTRule.h"

Expand All @@ -31,10 +33,16 @@ @interface SNTRuleTable ()
@property NSString *santadCertSHA;
@property NSString *launchdCertSHA;
@property NSDate *lastTransitiveRuleCulling;
@property NSDictionary *criticalSystemBinaries;
@property(readonly) NSArray *criticalSystemBinaryPaths;
@end

@implementation SNTRuleTable

- (NSArray *)criticalSystemBinaryPaths {
return @[ @"/usr/libexec/trustd", @"/usr/sbin/securityd", @"/usr/libexec/xpcproxy" ];
}

- (uint32_t)initializeDatabase:(FMDatabase *)db fromVersion:(uint32_t)version {
// Lock this database from other processes
[[db executeQuery:@"PRAGMA locking_mode = EXCLUSIVE;"] close];
Expand Down Expand Up @@ -64,7 +72,8 @@ - (uint32_t)initializeDatabase:(FMDatabase *)db fromVersion:(uint32_t)version {
// Save hashes of the signing certs for launchd and santad.
// Used to ensure rules for them are not removed.
self.santadCertSHA = [[[[MOLCodesignChecker alloc] initWithSelf] leafCertificate] SHA256];
self.launchdCertSHA = [[[[MOLCodesignChecker alloc] initWithPID:1] leafCertificate] SHA256];
MOLCodesignChecker *launchdCSInfo = [[MOLCodesignChecker alloc] initWithPID:1];
self.launchdCertSHA = launchdCSInfo.leafCertificate.SHA256;

// Ensure the certificates used to sign the running launchd/santad are whitelisted.
// If they weren't previously and the database is not new, log an error.
Expand All @@ -87,6 +96,34 @@ - (uint32_t)initializeDatabase:(FMDatabase *)db fromVersion:(uint32_t)version {
self.launchdCertSHA, @(SNTRuleStateWhitelist), @(SNTRuleTypeCertificate)];
}

// Setup critical system binaries
// TODO(tburgin): Add the Santa components to this feature and remove the santadCertSHA rule.
NSMutableDictionary *bins = [NSMutableDictionary dictionary];
for (NSString *path in self.criticalSystemBinaryPaths) {
SNTFileInfo *binInfo = [[SNTFileInfo alloc] initWithPath:path];
MOLCodesignChecker *csInfo = [binInfo codesignCheckerWithError:NULL];

// Make sure the critical system binary is signed by the same chain as launchd.
if ([csInfo signingInformationMatches:launchdCSInfo]) {
SNTCachedDecision *cd = [[SNTCachedDecision alloc] init];

cd.decision = SNTEventStateAllowBinary;
cd.decisionExtra = @"critical system binary";
cd.sha256 = binInfo.SHA256;

// Not needed, but nice for logging.
cd.certSHA256 = csInfo.leafCertificate.SHA256;
cd.certCommonName = csInfo.leafCertificate.commonName;

bins[binInfo.SHA256] = cd;
} else {
LOGE(@"Unable to validate critical system binary. pid 1: %@ and %@: %@ do not match.",
launchdCSInfo.leafCertificate, path, csInfo.leafCertificate);
}
}

self.criticalSystemBinaries = bins;

return newVersion;
}

Expand Down
34 changes: 20 additions & 14 deletions Source/santad/SNTExecutionController.m
Expand Up @@ -115,22 +115,28 @@ - (void)validateBinaryWithMessage:(santa_message_t)message {
[_driverManager postToKernelAction:ACTION_RESPOND_ACK forVnodeID:message.vnode_id];
}

// Get codesigning info about the file but only if it's a Mach-O.
MOLCodesignChecker *csInfo;
if (binInfo.isMachO) {
NSError *csError;
csInfo = [[MOLCodesignChecker alloc] initWithBinaryPath:binInfo.path
fileDescriptor:binInfo.fileHandle.fileDescriptor
error:&csError];
// Ignore codesigning if there are any errors with the signature.
if (csError) csInfo = nil;
// If the binary is a critical system binary, don't check its signature. The binary was validated
// by santad at startup.
SNTCachedDecision *cd = self.ruleTable.criticalSystemBinaries[binInfo.SHA256];
MOLCodesignChecker *csInfo; // Needed further down in this scope.
if (!cd) {
// Get codesigning info about the file but only if it's a Mach-O.
if (binInfo.isMachO) {
NSError *csError;
csInfo = [[MOLCodesignChecker alloc] initWithBinaryPath:binInfo.path
fileDescriptor:binInfo.fileHandle.fileDescriptor
error:&csError];
// Ignore codesigning if there are any errors with the signature.
if (csError) csInfo = nil;
}

// Actually make the decision (and refresh rule access timestamp).
cd = [self.policyProcessor decisionForFileInfo:binInfo
fileSHA256:nil
certificateSHA256:csInfo.leafCertificate.SHA256];
cd.certCommonName = csInfo.leafCertificate.commonName;
}

// Actually make the decision (and refresh rule access timestamp).
SNTCachedDecision *cd = [self.policyProcessor decisionForFileInfo:binInfo
fileSHA256:nil
certificateSHA256:csInfo.leafCertificate.SHA256];
cd.certCommonName = csInfo.leafCertificate.commonName;
cd.vnodeId = message.vnode_id;

// Formulate an initial action from the decision.
Expand Down