Skip to content

Commit

Permalink
Merge 77a3690 into 7513c75
Browse files Browse the repository at this point in the history
  • Loading branch information
mlw committed Feb 28, 2024
2 parents 7513c75 + 77a3690 commit 6f18eaa
Show file tree
Hide file tree
Showing 11 changed files with 203 additions and 52 deletions.
1 change: 1 addition & 0 deletions Source/common/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,7 @@ objc_library(
hdrs = ["SNTFileInfo.h"],
deps = [
":SNTLogging",
":SantaVnode",
"@FMDB",
"@MOLCodesignChecker",
],
Expand Down
2 changes: 2 additions & 0 deletions Source/common/SNTCachedDecision.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@
///
@interface SNTCachedDecision : NSObject

- (instancetype)init;
- (instancetype)initWithEndpointSecurityFile:(const es_file_t *)esFile;
- (instancetype)initWithVnode:(SantaVnode)vnode NS_DESIGNATED_INITIALIZER;

@property SantaVnode vnodeId;
@property SNTEventState decision;
Expand Down
10 changes: 9 additions & 1 deletion Source/common/SNTCachedDecision.mm
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,18 @@

@implementation SNTCachedDecision

- (instancetype)init {
return [self initWithVnode:(SantaVnode){}];
}

- (instancetype)initWithEndpointSecurityFile:(const es_file_t *)esFile {
return [self initWithVnode:SantaVnode::VnodeForFile(esFile)];
}

- (instancetype)initWithVnode:(SantaVnode)vnode {
self = [super init];
if (self) {
_vnodeId = SantaVnode::VnodeForFile(esFile);
_vnodeId = vnode;
}
return self;
}
Expand Down
7 changes: 7 additions & 0 deletions Source/common/SNTFileInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
#import <EndpointSecurity/EndpointSecurity.h>
#import <Foundation/Foundation.h>

#import "Source/common/SantaVnode.h"

@class MOLCodesignChecker;

///
Expand Down Expand Up @@ -220,6 +222,11 @@
///
- (NSUInteger)fileSize;

///
/// @return The devno/ino pair of the file
///
- (SantaVnode)vnode;

///
/// @return The underlying file handle.
///
Expand Down
2 changes: 2 additions & 0 deletions Source/common/SNTFileInfo.m
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ @interface SNTFileInfo ()
@property NSString *path;
@property NSFileHandle *fileHandle;
@property NSUInteger fileSize;
@property SantaVnode vnode;
@property NSString *fileOwnerHomeDir;
@property NSString *sha256Storage;

Expand Down Expand Up @@ -110,6 +111,7 @@ - (instancetype)initWithResolvedPath:(NSString *)path
}

_fileSize = fileStat->st_size;
_vnode = (SantaVnode){.fsid = fileStat->st_dev, .fileid = fileStat->st_ino};

if (_fileSize == 0) return nil;

Expand Down
1 change: 1 addition & 0 deletions Source/santad/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -1163,6 +1163,7 @@ santa_unit_test(
"//Source/common:SNTCachedDecision",
"//Source/common:SNTCommonEnums",
"//Source/common:SNTRule",
"//Source/common:SantaVnode",
"//Source/common:TestUtils",
"@OCMock",
],
Expand Down
57 changes: 36 additions & 21 deletions Source/santad/SNTCompilerController.mm
Original file line number Diff line number Diff line change
Expand Up @@ -65,19 +65,21 @@ - (void)setProcess:(const audit_token_t &)tok isCompiler:(bool)isCompiler {
// Adds a fake cached decision to SNTDecisionCache for pending files. If the file
// is executed before we can create a transitive rule for it, then we can at
// least log the pending decision info.
- (void)saveFakeDecision:(const es_file_t *)esFile {
SNTCachedDecision *cd = [[SNTCachedDecision alloc] initWithEndpointSecurityFile:esFile];
- (void)saveFakeDecision:(SNTFileInfo *)fileInfo {
SNTCachedDecision *cd = [[SNTCachedDecision alloc] initWithVnode:fileInfo.vnode];
cd.decision = SNTEventStateAllowPendingTransitive;
cd.sha256 = @"pending";
[[SNTDecisionCache sharedCache] cacheDecision:cd];
}

- (void)removeFakeDecision:(const es_file_t *)esFile {
[[SNTDecisionCache sharedCache] forgetCachedDecisionForFile:esFile->stat];
- (void)removeFakeDecision:(SNTFileInfo *)fileInfo {
[[SNTDecisionCache sharedCache] forgetCachedDecisionForVnode:fileInfo.vnode];
}

- (BOOL)handleEvent:(const Message &)esMsg withLogger:(std::shared_ptr<Logger>)logger {
const es_file_t *targetFile = NULL;
SNTFileInfo *targetFile;
NSString *targetPath;
NSError *error;

switch (esMsg->event_type) {
case ES_EVENT_TYPE_NOTIFY_CLOSE:
Expand All @@ -90,7 +92,9 @@ - (BOOL)handleEvent:(const Message &)esMsg withLogger:(std::shared_ptr<Logger>)l
return NO;
}

targetFile = esMsg->event.close.target;
targetPath = @(esMsg->event.close.target->path.data);
targetFile = [[SNTFileInfo alloc] initWithEndpointSecurityFile:esMsg->event.close.target
error:&error];

break;
case ES_EVENT_TYPE_NOTIFY_RENAME:
Expand All @@ -105,7 +109,24 @@ - (BOOL)handleEvent:(const Message &)esMsg withLogger:(std::shared_ptr<Logger>)l
return NO;
}

targetFile = esMsg->event.rename.source;
targetFile = [[SNTFileInfo alloc] initWithEndpointSecurityFile:esMsg->event.rename.source
error:&error];
if (!targetFile) {
LOGD(@"Unable to locate source file for rename event while creating transitive. Falling "
@"back to destination. Path: %s, Error: %@",
esMsg->event.rename.source->path.data, error);
if (esMsg->event.rename.destination_type == ES_DESTINATION_TYPE_EXISTING_FILE) {
targetPath = @(esMsg->event.rename.destination.existing_file->path.data);
targetFile = [[SNTFileInfo alloc]
initWithEndpointSecurityFile:esMsg->event.rename.destination.existing_file
error:&error];
} else {
targetPath = [NSString
stringWithFormat:@"%s/%s", esMsg->event.rename.destination.new_path.dir->path.data,
esMsg->event.rename.destination.new_path.filename.data];
targetFile = [[SNTFileInfo alloc] initWithPath:targetPath error:&error];
}
}

break;
case ES_EVENT_TYPE_NOTIFY_EXIT:
Expand All @@ -119,6 +140,9 @@ - (BOOL)handleEvent:(const Message &)esMsg withLogger:(std::shared_ptr<Logger>)l
[self createTransitiveRule:esMsg target:targetFile logger:logger];
return YES;
} else {
LOGD(@"Unable to create SNTFileInfo while attempting to create transitive rule. Event: %d | "
@"Path: %@ | Error: %@",
(int)esMsg->event_type, targetPath, error);
return NO;
}
}
Expand All @@ -127,30 +151,21 @@ - (BOOL)handleEvent:(const Message &)esMsg withLogger:(std::shared_ptr<Logger>)l
// compiler. It checks if the closed file is executable, and if so, transitively allowlists it.
// The passed in message contains the pid of the writing process and path of closed file.
- (void)createTransitiveRule:(const Message &)esMsg
target:(const es_file_t *)targetFile
target:(SNTFileInfo *)targetFile
logger:(std::shared_ptr<Logger>)logger {
NSError *error = nil;
SNTFileInfo *fi = [[SNTFileInfo alloc] initWithEndpointSecurityFile:targetFile error:&error];
if (error) {
LOGD(@"Unable to create SNTFileInfo while attempting to create transitive rule. Event: %d | "
@"Path: %@ | Error: %@",
(int)esMsg->event_type, @(targetFile->path.data), error);
return;
}

[self saveFakeDecision:targetFile];

// Check if this file is an executable.
if (fi.isExecutable) {
if (targetFile.isExecutable) {
// Check if there is an existing (non-transitive) rule for this file. We leave existing rules
// alone, so that a allowlist or blocklist rule can't be overwritten by a transitive one.
SNTRuleTable *ruleTable = [SNTDatabaseController ruleTable];
SNTRule *prevRule = [ruleTable ruleForIdentifiers:(struct RuleIdentifiers){
.binarySHA256 = fi.SHA256,
.binarySHA256 = targetFile.SHA256,
}];
if (!prevRule || prevRule.state == SNTRuleStateAllowTransitive) {
// Construct a new transitive allowlist rule for the executable.
SNTRule *rule = [[SNTRule alloc] initWithIdentifier:fi.SHA256
SNTRule *rule = [[SNTRule alloc] initWithIdentifier:targetFile.SHA256
state:SNTRuleStateAllowTransitive
type:SNTRuleTypeBinary
customMsg:@""];
Expand All @@ -160,7 +175,7 @@ - (void)createTransitiveRule:(const Message &)esMsg
if (![ruleTable addRules:@[ rule ] ruleCleanup:SNTRuleCleanupNone error:&err]) {
LOGE(@"unable to add new transitive rule to database: %@", err.localizedDescription);
} else {
logger->LogAllowlist(esMsg, [fi.SHA256 UTF8String]);
logger->LogAllowlist(esMsg, [targetFile.SHA256 UTF8String]);
}
}
}
Expand Down
Loading

0 comments on commit 6f18eaa

Please sign in to comment.