mirror of
https://github.com/google/santa.git
synced 2026-01-15 01:08:12 -05:00
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ad1868a50f | ||
|
|
78643d3c49 |
@@ -362,7 +362,7 @@ extern NSString *const NSURLQuarantinePropertiesKey WEAK_IMPORT_ATTRIBUTE;
|
||||
while (pathComponents.count > 1) {
|
||||
NSBundle *bndl = [NSBundle bundleWithPath:[NSString pathWithComponents:pathComponents]];
|
||||
if ([bndl objectForInfoDictionaryKey:@"CFBundleIdentifier"]) {
|
||||
if (!ancestor ||
|
||||
if ((!ancestor && bndl.bundlePath.pathExtension.length) ||
|
||||
[[self allowedAncestorExtensions] containsObject:bndl.bundlePath.pathExtension]) {
|
||||
bundle = bndl;
|
||||
}
|
||||
|
||||
@@ -88,7 +88,10 @@ void logMessage(LogLevel level, FILE *destination, NSString *format, ...) {
|
||||
break;
|
||||
case LOG_LEVEL_DEBUG:
|
||||
levelName = "D";
|
||||
syslogLevel = ASL_LEVEL_DEBUG;
|
||||
// Log debug messages at the same ASL level as INFO.
|
||||
// While it would make sense to use DEBUG, watching debug-level logs
|
||||
// in Console means enabling all debug logs, which is absurdly noisy.
|
||||
syslogLevel = ASL_LEVEL_NOTICE;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
#import "Source/common/SantaCache.h"
|
||||
#import "Source/common/SNTLogging.h"
|
||||
|
||||
#include <atomic>
|
||||
#include <bsm/libbsm.h>
|
||||
#include <EndpointSecurity/EndpointSecurity.h>
|
||||
|
||||
uint64_t GetCurrentUptime() {
|
||||
@@ -28,7 +28,6 @@ template<> uint64_t SantaCacheHasher<santa_vnode_id_t>(santa_vnode_id_t const& t
|
||||
}
|
||||
|
||||
@implementation SNTCachingEndpointSecurityManager {
|
||||
std::atomic<bool> _compilerPIDs[PID_MAX];
|
||||
SantaCache<santa_vnode_id_t, uint64_t> *_decisionCache;
|
||||
}
|
||||
|
||||
@@ -56,10 +55,20 @@ template<> uint64_t SantaCacheHasher<santa_vnode_id_t>(santa_vnode_id_t const& t
|
||||
// If item is in cache but hasn't received a response yet, sleep for a bit.
|
||||
// If item is not in cache, break out of loop and forward request to callback.
|
||||
if (RESPONSE_VALID(return_action)) {
|
||||
if (return_action == ACTION_RESPOND_ALLOW) {
|
||||
es_respond_auth_result(self.client, m, ES_AUTH_RESULT_ALLOW, true);
|
||||
} else {
|
||||
es_respond_auth_result(self.client, m, ES_AUTH_RESULT_DENY, false);
|
||||
switch (return_action) {
|
||||
case ACTION_RESPOND_ALLOW:
|
||||
es_respond_auth_result(self.client, m, ES_AUTH_RESULT_ALLOW, true);
|
||||
break;
|
||||
case ACTION_RESPOND_ALLOW_COMPILER: {
|
||||
pid_t pid = audit_token_to_pid(m->process->audit_token);
|
||||
[self setIsCompilerPID:pid];
|
||||
// Don't let ES cache compilers
|
||||
es_respond_auth_result(self.client, m, ES_AUTH_RESULT_ALLOW, false);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
es_respond_auth_result(self.client, m, ES_AUTH_RESULT_DENY, false);
|
||||
break;
|
||||
}
|
||||
return YES;
|
||||
} else if (return_action == ACTION_REQUEST_BINARY || return_action == ACTION_RESPOND_ACK) {
|
||||
@@ -70,7 +79,7 @@ template<> uint64_t SantaCacheHasher<santa_vnode_id_t>(santa_vnode_id_t const& t
|
||||
}
|
||||
}
|
||||
|
||||
[self addToCache:vnode_id decision:ACTION_REQUEST_BINARY timeout:0];
|
||||
[self addToCache:vnode_id decision:ACTION_REQUEST_BINARY currentTicks:0];
|
||||
return NO;
|
||||
}
|
||||
|
||||
@@ -79,25 +88,24 @@ template<> uint64_t SantaCacheHasher<santa_vnode_id_t>(santa_vnode_id_t const& t
|
||||
es_respond_result_t ret;
|
||||
switch (action) {
|
||||
case ACTION_RESPOND_ALLOW_COMPILER:
|
||||
if (sm.pid >= PID_MAX) {
|
||||
LOGE(@"Unable to watch compiler pid=%d >= pid_max=%d", sm.pid, PID_MAX);
|
||||
} else {
|
||||
LOGD(@"Watching compiler pid=%d path=%s", sm.pid, sm.path);
|
||||
self->_compilerPIDs[sm.pid].store(true);
|
||||
}
|
||||
// Allow the exec, but don't cache the decision so subsequent execs of the compiler get
|
||||
// marked appropriately.
|
||||
[self setIsCompilerPID:sm.pid];
|
||||
|
||||
// Allow the exec and cache in our internal cache but don't let ES cache, because then
|
||||
// we won't see future execs of the compiler in order to record the PID.
|
||||
[self addToCache:sm.vnode_id
|
||||
decision:ACTION_RESPOND_ALLOW_COMPILER
|
||||
currentTicks:GetCurrentUptime()];
|
||||
ret = es_respond_auth_result(self.client, (es_message_t *)sm.es_message,
|
||||
ES_AUTH_RESULT_ALLOW, false);
|
||||
break;
|
||||
case ACTION_RESPOND_ALLOW:
|
||||
case ACTION_RESPOND_ALLOW_PENDING_TRANSITIVE:
|
||||
[self addToCache:sm.vnode_id decision:ACTION_RESPOND_ALLOW timeout:GetCurrentUptime()];
|
||||
[self addToCache:sm.vnode_id decision:ACTION_RESPOND_ALLOW currentTicks:GetCurrentUptime()];
|
||||
ret = es_respond_auth_result(self.client, (es_message_t *)sm.es_message,
|
||||
ES_AUTH_RESULT_ALLOW, true);
|
||||
break;
|
||||
case ACTION_RESPOND_DENY:
|
||||
[self addToCache:sm.vnode_id decision:ACTION_RESPOND_DENY timeout:GetCurrentUptime()];
|
||||
[self addToCache:sm.vnode_id decision:ACTION_RESPOND_DENY currentTicks:GetCurrentUptime()];
|
||||
OS_FALLTHROUGH;
|
||||
case ACTION_RESPOND_TOOLONG:
|
||||
ret = es_respond_auth_result(self.client, (es_message_t *)sm.es_message,
|
||||
@@ -114,7 +122,7 @@ template<> uint64_t SantaCacheHasher<santa_vnode_id_t>(santa_vnode_id_t const& t
|
||||
|
||||
- (void)addToCache:(santa_vnode_id_t)identifier
|
||||
decision:(santa_action_t)decision
|
||||
timeout:(uint64_t)microsecs {
|
||||
currentTicks:(uint64_t)microsecs {
|
||||
switch (decision) {
|
||||
case ACTION_REQUEST_BINARY:
|
||||
_decisionCache->set(identifier, (uint64_t)ACTION_REQUEST_BINARY << 56, 0);
|
||||
|
||||
@@ -25,6 +25,10 @@ const pid_t PID_MAX = 99999;
|
||||
@interface SNTEndpointSecurityManager : NSObject<SNTEventProvider>
|
||||
- (santa_vnode_id_t)vnodeIDForFile:(es_file_t *)file;
|
||||
|
||||
- (BOOL)isCompilerPID:(pid_t)pid;
|
||||
- (void)setIsCompilerPID:(pid_t)pid;
|
||||
- (void)setNotCompilerPID:(pid_t)pid;
|
||||
|
||||
@property(readonly, nonatomic) es_client_t *client;
|
||||
|
||||
@end
|
||||
|
||||
@@ -25,7 +25,9 @@
|
||||
#include <libproc.h>
|
||||
|
||||
|
||||
@interface SNTEndpointSecurityManager ()
|
||||
@interface SNTEndpointSecurityManager () {
|
||||
std::atomic<bool> _compilerPIDs[PID_MAX];
|
||||
}
|
||||
|
||||
@property(nonatomic) SNTPrefixTree *prefixTree;
|
||||
@property(nonatomic, copy) void (^decisionCallback)(santa_message_t);
|
||||
@@ -36,9 +38,7 @@
|
||||
|
||||
@end
|
||||
|
||||
@implementation SNTEndpointSecurityManager {
|
||||
std::atomic<bool> _compilerPIDs[PID_MAX];
|
||||
}
|
||||
@implementation SNTEndpointSecurityManager
|
||||
|
||||
- (instancetype)init API_AVAILABLE(macos(10.15)) {
|
||||
self = [super init];
|
||||
@@ -107,7 +107,7 @@
|
||||
[self removeCacheEntryForVnodeID:[self vnodeIDForFile:m->event.close.target]];
|
||||
|
||||
// Create a transitive rule if the file was modified by a running compiler
|
||||
if (pid && pid < PID_MAX && self->_compilerPIDs[pid].load()) {
|
||||
if ([self isCompilerPID:pid]) {
|
||||
santa_message_t sm = {};
|
||||
BOOL truncated = [self populateBufferFromESFile:m->event.close.target
|
||||
buffer:sm.path
|
||||
@@ -117,6 +117,9 @@
|
||||
sm.path, pid);
|
||||
break;
|
||||
}
|
||||
if ([@(sm.path) hasPrefix:@"/dev/"]) {
|
||||
break;
|
||||
}
|
||||
sm.action = ACTION_NOTIFY_WHITELIST;
|
||||
sm.pid = pid;
|
||||
sm.pidversion = pidversion;
|
||||
@@ -129,7 +132,7 @@
|
||||
}
|
||||
case ES_EVENT_TYPE_NOTIFY_RENAME: {
|
||||
// Create a transitive rule if the file was renamed by a running compiler
|
||||
if (pid && pid < PID_MAX && self->_compilerPIDs[pid].load()) {
|
||||
if ([self isCompilerPID:pid]) {
|
||||
santa_message_t sm = {};
|
||||
BOOL truncated = [self populateRenamedNewPathFromESMessage:m->event.rename
|
||||
buffer:sm.path
|
||||
@@ -139,6 +142,9 @@
|
||||
sm.path, pid);
|
||||
break;
|
||||
}
|
||||
if ([@(sm.path) hasPrefix:@"/dev/"]) {
|
||||
break;
|
||||
}
|
||||
sm.action = ACTION_NOTIFY_WHITELIST;
|
||||
sm.pid = pid;
|
||||
sm.pidversion = pidversion;
|
||||
@@ -151,7 +157,7 @@
|
||||
}
|
||||
case ES_EVENT_TYPE_NOTIFY_EXIT: {
|
||||
// Update the set of running compiler PIDs
|
||||
if (pid && pid < PID_MAX) self->_compilerPIDs[pid].store(false);
|
||||
[self setNotCompilerPID:pid];
|
||||
|
||||
// Skip the standard pipeline and just log.
|
||||
if (![config enableForkAndExitLogging]) return;
|
||||
@@ -191,12 +197,12 @@
|
||||
|
||||
switch (m->action_type) {
|
||||
case ES_ACTION_TYPE_AUTH: {
|
||||
// Create a timer to deny the execution 2 seconds before the deadline,
|
||||
// Create a timer to deny the execution 5 seconds before the deadline,
|
||||
// if a response hasn't already been sent. This block will still be enqueued if
|
||||
// the the deadline - 2 secs is < DISPATCH_TIME_NOW.
|
||||
// As of 10.15.2, a typical deadline is 60 seconds.
|
||||
// the the deadline - 5 secs is < DISPATCH_TIME_NOW.
|
||||
// As of 10.15.5, a typical deadline is 60 seconds.
|
||||
auto responded = std::make_shared<std::atomic<bool>>(false);
|
||||
dispatch_after(dispatch_time(m->deadline, NSEC_PER_SEC * -2), self.esAuthQueue, ^(void) {
|
||||
dispatch_after(dispatch_time(m->deadline, NSEC_PER_SEC * -5), self.esAuthQueue, ^(void) {
|
||||
if (responded->load()) return;
|
||||
LOGE(@"Deadline reached: deny pid=%d ret=%d",
|
||||
pid, es_respond_auth_result(self.client, m, ES_AUTH_RESULT_DENY, false));
|
||||
@@ -446,12 +452,8 @@
|
||||
es_respond_result_t ret;
|
||||
switch (action) {
|
||||
case ACTION_RESPOND_ALLOW_COMPILER:
|
||||
if (sm.pid >= PID_MAX) {
|
||||
LOGE(@"Unable to watch compiler pid=%d >= pid_max=%d", sm.pid, PID_MAX);
|
||||
} else {
|
||||
LOGD(@"Watching compiler pid=%d path=%s", sm.pid, sm.path);
|
||||
self->_compilerPIDs[sm.pid].store(true);
|
||||
}
|
||||
[self setIsCompilerPID:sm.pid];
|
||||
|
||||
// Allow the exec, but don't cache the decision so subsequent execs of the compiler get
|
||||
// marked appropriately.
|
||||
ret = es_respond_auth_result(self.client, (es_message_t *)sm.es_message,
|
||||
@@ -564,4 +566,23 @@
|
||||
};
|
||||
}
|
||||
|
||||
- (BOOL)isCompilerPID:(pid_t)pid {
|
||||
return (pid && pid < PID_MAX && self->_compilerPIDs[pid].load());
|
||||
}
|
||||
|
||||
- (void)setIsCompilerPID:(pid_t)pid {
|
||||
if (pid < 1) {
|
||||
LOGE(@"Unable to watch compiler pid=%d", pid);
|
||||
} else if (pid >= PID_MAX) {
|
||||
LOGE(@"Unable to watch compiler pid=%d >= PID_MAX(%d)", pid, PID_MAX);
|
||||
} else {
|
||||
self->_compilerPIDs[pid].store(true);
|
||||
LOGD(@"Watching compiler pid=%d", pid);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setNotCompilerPID:(pid_t)pid {
|
||||
if (pid && pid < PID_MAX) self->_compilerPIDs[pid].store(false);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
"""The version for all Santa components."""
|
||||
|
||||
SANTA_VERSION = "2021.2"
|
||||
SANTA_VERSION = "2021.3"
|
||||
|
||||
Reference in New Issue
Block a user