Adopt new ES APIs to watch target paths in tamper client (#984)

This commit is contained in:
Matt W
2022-12-22 22:49:25 +01:00
committed by GitHub
parent 57285c48dd
commit 42cf1b232a
6 changed files with 63 additions and 13 deletions

View File

@@ -295,6 +295,7 @@ objc_library(
":Metrics",
":SNTEndpointSecurityClient",
":SNTEndpointSecurityEventHandler",
":WatchItemPolicy",
"//Source/common:SNTLogging",
],
)
@@ -1185,6 +1186,7 @@ santa_unit_test(
":Metrics",
":MockEndpointSecurityAPI",
":SNTEndpointSecurityTamperResistance",
":WatchItemPolicy",
"//Source/common:SNTLogging",
"//Source/common:TestUtils",
"@OCMock",

View File

@@ -21,6 +21,10 @@
#include <stdlib.h>
#include <sys/qos.h>
#include <set>
#include <string>
#include <string_view>
#include "Source/common/BranchPrediction.h"
#import "Source/common/SNTConfigurator.h"
#import "Source/common/SNTLogging.h"
@@ -40,6 +44,9 @@ using santa::santad::event_providers::endpoint_security::EndpointSecurityAPI;
using santa::santad::event_providers::endpoint_security::EnrichedMessage;
using santa::santad::event_providers::endpoint_security::Message;
constexpr std::string_view kProtectedFiles[] = {"/private/var/db/santa/rules.db",
"/private/var/db/santa/events.db"};
@interface SNTEndpointSecurityClient ()
@property int64_t deadlineMarginMS;
@end
@@ -296,12 +303,28 @@ using santa::santad::event_providers::endpoint_security::Message;
});
}
+ (bool)isDatabasePath:(const std::string_view)path {
+ (std::set<std::string>)getProtectedPaths {
std::set<std::string> protectedPathsCopy;
for (size_t i = 0; i < sizeof(kProtectedFiles) / sizeof(kProtectedFiles[0]); i++) {
protectedPathsCopy.insert(std::string(kProtectedFiles[i]));
}
return protectedPathsCopy;
}
+ (bool)isProtectedPath:(const std::string_view)path {
// TODO(mlw): These values should come from `SNTDatabaseController`. But right
// now they live as NSStrings. We should make them `std::string_view` types
// in order to use them here efficiently, but will need to make the
// `SNTDatabaseController` an ObjC++ file.
return (path == "/private/var/db/santa/rules.db" || path == "/private/var/db/santa/events.db");
for (size_t i = 0; i < sizeof(kProtectedFiles) / sizeof(kProtectedFiles[0]); i++) {
if (path == kProtectedFiles[i]) {
return true;
}
}
return false;
}
@end

View File

@@ -86,7 +86,8 @@
- (bool)clearCache;
+ (bool)isDatabasePath:(const std::string_view)path;
+ (std::set<std::string>)getProtectedPaths;
+ (bool)isProtectedPath:(const std::string_view)path;
+ (bool)populateAuditTokenSelf:(audit_token_t *)tok;
@end

View File

@@ -413,11 +413,11 @@ using santa::santad::event_providers::endpoint_security::Message;
XCTBubbleMockVerifyAndClearExpectations(mockESApi.get());
}
- (void)testIsDatabasePath {
XCTAssertTrue([SNTEndpointSecurityClient isDatabasePath:"/private/var/db/santa/rules.db"]);
XCTAssertTrue([SNTEndpointSecurityClient isDatabasePath:"/private/var/db/santa/events.db"]);
- (void)testIsProtectedPath {
XCTAssertTrue([SNTEndpointSecurityClient isProtectedPath:"/private/var/db/santa/rules.db"]);
XCTAssertTrue([SNTEndpointSecurityClient isProtectedPath:"/private/var/db/santa/events.db"]);
XCTAssertFalse([SNTEndpointSecurityClient isDatabasePath:"/not/a/db/path"]);
XCTAssertFalse([SNTEndpointSecurityClient isProtectedPath:"/not/a/db/path"]);
}
- (void)testProcessMessageHandlerBadEventType {

View File

@@ -18,10 +18,12 @@
#include <string.h>
#import "Source/common/SNTLogging.h"
#include "Source/santad/DataLayer/WatchItemPolicy.h"
#include "Source/santad/EventProviders/EndpointSecurity/Message.h"
#include "Source/santad/Metrics.h"
using santa::santad::EventDisposition;
using santa::santad::data_layer::WatchItemPathType;
using santa::santad::event_providers::endpoint_security::EndpointSecurityAPI;
using santa::santad::event_providers::endpoint_security::Message;
using santa::santad::logs::endpoint_security::Logger;
@@ -56,7 +58,7 @@ static constexpr std::string_view kSantaKextIdentifier = "com.google.santa-drive
switch (esMsg->event_type) {
case ES_EVENT_TYPE_AUTH_UNLINK: {
if ([SNTEndpointSecurityTamperResistance
isDatabasePath:esMsg->event.unlink.target->path.data]) {
isProtectedPath:esMsg->event.unlink.target->path.data]) {
result = ES_AUTH_RESULT_DENY;
LOGW(@"Preventing attempt to delete Santa databases!");
}
@@ -65,7 +67,7 @@ static constexpr std::string_view kSantaKextIdentifier = "com.google.santa-drive
case ES_EVENT_TYPE_AUTH_RENAME: {
if ([SNTEndpointSecurityTamperResistance
isDatabasePath:esMsg->event.rename.source->path.data]) {
isProtectedPath:esMsg->event.rename.source->path.data]) {
result = ES_AUTH_RESULT_DENY;
LOGW(@"Preventing attempt to rename Santa databases!");
break;
@@ -73,7 +75,7 @@ static constexpr std::string_view kSantaKextIdentifier = "com.google.santa-drive
if (esMsg->event.rename.destination_type == ES_DESTINATION_TYPE_EXISTING_FILE) {
if ([SNTEndpointSecurityTamperResistance
isDatabasePath:esMsg->event.rename.destination.existing_file->path.data]) {
isProtectedPath:esMsg->event.rename.destination.existing_file->path.data]) {
result = ES_AUTH_RESULT_DENY;
LOGW(@"Preventing attempt to overwrite Santa databases!");
break;
@@ -108,9 +110,20 @@ static constexpr std::string_view kSantaKextIdentifier = "com.google.santa-drive
}
- (void)enable {
// TODO(mlw): For macOS 13, use new mute and invert APIs to limit the
// messages sent for these events to the Santa-specific directories
// checked in the `handleMessage:` method.
[super enableTargetPathWatching];
[super unmuteEverything];
// Get the set of protected paths
std::set<std::string> protectedPaths = [SNTEndpointSecurityTamperResistance getProtectedPaths];
// Iterate the set, and create a vector of literals to mute
std::vector<std::pair<std::string, WatchItemPathType>> watchPaths;
for (const auto &path : protectedPaths) {
watchPaths.push_back({path, WatchItemPathType::kLiteral});
}
// Begin watching the protected set
[super muteTargetPaths:watchPaths];
[super subscribeAndClearCache:{
ES_EVENT_TYPE_AUTH_KEXTLOAD,

View File

@@ -24,6 +24,7 @@
#include <set>
#include "Source/common/TestUtils.h"
#include "Source/santad/DataLayer/WatchItemPolicy.h"
#include "Source/santad/EventProviders/EndpointSecurity/Client.h"
#include "Source/santad/EventProviders/EndpointSecurity/Message.h"
#include "Source/santad/EventProviders/EndpointSecurity/MockEndpointSecurityAPI.h"
@@ -31,6 +32,7 @@
#import "Source/santad/Metrics.h"
using santa::santad::EventDisposition;
using santa::santad::data_layer::WatchItemPathType;
using santa::santad::event_providers::endpoint_security::Client;
using santa::santad::event_providers::endpoint_security::Message;
@@ -61,6 +63,15 @@ static constexpr std::string_view kSantaKextIdentifier = "com.google.santa-drive
.WillOnce(testing::Return(true)))
.WillOnce(testing::Return(true));
// Setup mocks to handle inverting target path muting
EXPECT_CALL(*mockESApi, InvertTargetPathMuting).WillOnce(testing::Return(true));
EXPECT_CALL(*mockESApi, UnmuteAllPaths).WillOnce(testing::Return(true));
EXPECT_CALL(*mockESApi, UnmuteAllTargetPaths).WillOnce(testing::Return(true));
// Setup mocks to handle muting the rules db and events db
EXPECT_CALL(*mockESApi, MuteTargetPath(testing::_, testing::_, WatchItemPathType::kLiteral))
.WillRepeatedly(testing::Return(true));
SNTEndpointSecurityTamperResistance *tamperClient =
[[SNTEndpointSecurityTamperResistance alloc] initWithESAPI:mockESApi
metrics:nullptr