Skip to content

Commit

Permalink
Merge 343ae88 into 471ae89
Browse files Browse the repository at this point in the history
  • Loading branch information
tnek committed Aug 12, 2021
2 parents 471ae89 + 343ae88 commit 7a6b18b
Show file tree
Hide file tree
Showing 2 changed files with 147 additions and 6 deletions.
27 changes: 21 additions & 6 deletions Source/santad/EventProviders/SNTEndpointSecurityManager.mm
Original file line number Diff line number Diff line change
Expand Up @@ -303,8 +303,7 @@ - (void)messageHandler:(es_message_t *)m API_AVAILABLE(macos(10.15)) {
NSString *path = [[NSString alloc] initWithBytes:pathToken.data
length:pathToken.length
encoding:NSUTF8StringEncoding];
if (([path isEqualToString:@"/private/var/db/santa/rules.db"] ||
[path isEqualToString:@"/private/var/db/santa/events.db"]) &&
if ([self isDatabasePath:path] &&
audit_token_to_pid(m->process->audit_token) != self.selfPID) {
LOGW(@"Preventing attempt to delete Santa databases!");
es_respond_auth_result(self.client, m, ES_AUTH_RESULT_DENY, true);
Expand All @@ -319,15 +318,26 @@ - (void)messageHandler:(es_message_t *)m API_AVAILABLE(macos(10.15)) {
length:pathToken.length
encoding:NSUTF8StringEncoding];

if (([path isEqualToString:@"/private/var/db/santa/rules.db"] ||
[path isEqualToString:@"/private/var/db/santa/events.db"]) &&
if ([self isDatabasePath:path] &&
audit_token_to_pid(m->process->audit_token) != self.selfPID) {
LOGW(@"Preventing attempt to rename Santa databases!");
es_respond_auth_result(self.client, m, ES_AUTH_RESULT_DENY, true);
return;
}
es_respond_auth_result(self.client, m, ES_AUTH_RESULT_ALLOW, true);
return;
if (m->event.rename.destination_type == ES_DESTINATION_TYPE_EXISTING_FILE) {
es_string_token_t destToken = m->event.rename.destination.existing_file->path;
NSString *destPath = [[NSString alloc] initWithBytes:destToken.data
length:destToken.length
encoding:NSUTF8StringEncoding];
if ([self isDatabasePath:destPath] &&
audit_token_to_pid(m->process->audit_token) != self.selfPID) {
LOGW(@"Preventing attempt to overwrite Santa databases!");
es_respond_auth_result(self.client, m, ES_AUTH_RESULT_DENY, true);
return;
}
es_respond_auth_result(self.client, m, ES_AUTH_RESULT_ALLOW, true);
return;
}
}
case ES_EVENT_TYPE_AUTH_KEXTLOAD: {
es_string_token_t identifier = m->event.kextload.identifier;
Expand Down Expand Up @@ -561,6 +571,11 @@ - (santa_vnode_id_t)vnodeIDForFile:(es_file_t *)file {
};
}

- (BOOL)isDatabasePath:(NSString *)path {
return [path isEqualToString:@"/private/var/db/santa/rules.db"] ||
[path isEqualToString:@"/private/var/db/santa/events.db"];
}

- (BOOL)isCompilerPID:(pid_t)pid {
return (pid && pid < PID_MAX && self->_compilerPIDs[pid].load());
}
Expand Down
126 changes: 126 additions & 0 deletions Source/santad/EventProviders/SNTEndpointSecurityManagerTest.mm
Original file line number Diff line number Diff line change
Expand Up @@ -200,4 +200,130 @@ - (void)testSkipOtherESEvents {
XCTAssertEqual(got.result, ES_AUTH_RESULT_ALLOW);
}

- (void)testRenameOverwriteRulesDB {
for (const NSString *testPath in @[ kEventsDBPath, kRulesDBPath ]) {
MockEndpointSecurity *mockES = [MockEndpointSecurity mockEndpointSecurity];
[mockES reset];
SNTEndpointSecurityManager *snt = [[SNTEndpointSecurityManager alloc] init];

XCTestExpectation *expectation = [self expectationWithDescription:@"Wait for response from ES"];
__block NSMutableArray<ESResponse *> *events = [NSMutableArray array];
__block ESResponse *got = nil;
[mockES registerResponseCallback:^(ESResponse *r) {
got = r;
[expectation fulfill];
}];
es_file_t otherFile = {.path = MakeStringToken(@"/some/other/path")};
es_file_t dbFile = {.path = MakeStringToken(testPath)};

es_event_rename_t renameEvent = {
.destination_type = ES_DESTINATION_TYPE_EXISTING_FILE,
.source = &otherFile,
.destination = {.existing_file = &dbFile},
};

es_file_t otherBinary = {.path = MakeStringToken(@"somebinary")};
es_process_t proc = {
.executable = &otherBinary,
.is_es_client = false,
.codesigning_flags = 570509313,
.session_id = 12345,
.group_id = 12345,
.ppid = 12345,
.original_ppid = 12345,
.is_platform_binary = false,
};

es_events_t event = {.rename = renameEvent};
es_message_t m = {
.version = 4,
.event_type = ES_EVENT_TYPE_AUTH_RENAME,
.event = event,
.mach_time = DISPATCH_TIME_NOW,
.action_type = ES_ACTION_TYPE_AUTH,
.deadline = DISPATCH_TIME_FOREVER,
.process = &proc,
.seq_num = 1337,
};
[mockES triggerHandler:&m];

[self waitForExpectationsWithTimeout:10.0
handler:^(NSError *error) {
if (error) {
XCTFail(@"Santa auth test timed out with error: %@", error);
}
}];

XCTAssertEqual(got.result, ES_AUTH_RESULT_DENY, @"Failed to deny rename overwrite of %@",
testPath);
XCTAssertTrue(got.shouldCache, @"Failed to cache rename deny decision of %@", testPath);
}
}

- (void)testRenameRulesDB {
for (const NSString *testPath in @[ kEventsDBPath, kRulesDBPath ]) {
MockEndpointSecurity *mockES = [MockEndpointSecurity mockEndpointSecurity];
[mockES reset];
SNTEndpointSecurityManager *snt = [[SNTEndpointSecurityManager alloc] init];

XCTestExpectation *expectation = [self expectationWithDescription:@"Wait for response from ES"];
__block NSMutableArray<ESResponse *> *events = [NSMutableArray array];
__block ESResponse *got = nil;
[mockES registerResponseCallback:^(ESResponse *r) {
got = r;
[expectation fulfill];
}];
es_file_t otherFile = {.path = MakeStringToken(@"/some/other/path")};
es_file_t dbFile = {.path = MakeStringToken(testPath)};

es_event_rename_t renameEvent = {
.source = &dbFile,
.destination_type = ES_DESTINATION_TYPE_NEW_PATH,
.destination =
{
.new_path =
{
.dir = &otherFile,
.filename = MakeStringToken(@"someotherfilename"),
},
},
};

es_file_t otherBinary = {.path = MakeStringToken(@"somebinary")};
es_process_t proc = {
.executable = &otherBinary,
.is_es_client = false,
.codesigning_flags = 570509313,
.session_id = 12345,
.group_id = 12345,
.ppid = 12345,
.original_ppid = 12345,
.is_platform_binary = false,
};

es_events_t event = {.rename = renameEvent};
es_message_t m = {
.version = 4,
.event_type = ES_EVENT_TYPE_AUTH_RENAME,
.event = event,
.mach_time = DISPATCH_TIME_NOW,
.action_type = ES_ACTION_TYPE_AUTH,
.deadline = DISPATCH_TIME_FOREVER,
.process = &proc,
.seq_num = 1337,
};
[mockES triggerHandler:&m];

[self waitForExpectationsWithTimeout:10.0
handler:^(NSError *error) {
if (error) {
XCTFail(@"Santa auth test timed out with error: %@", error);
}
}];

XCTAssertEqual(got.result, ES_AUTH_RESULT_DENY, @"Failed to deny rename of %@", testPath);
XCTAssertTrue(got.shouldCache, @"Failed to cache rename deny decision of %@", testPath);
}
}

@end

0 comments on commit 7a6b18b

Please sign in to comment.