Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Standalone: Switch to a hold-and-ask model (part 1) #174

Merged
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 7 additions & 11 deletions Source/common/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,10 @@ objc_library(
cc_library(
name = "SantaCache",
hdrs = ["SantaCache.h"],
deps = [":BranchPrediction"],
deps = [
":BranchPrediction",
"@com_google_absl//absl/hash",
],
)

santa_unit_test(
Expand Down Expand Up @@ -120,6 +123,9 @@ objc_library(
objc_library(
name = "SantaVnode",
hdrs = ["SantaVnode.h"],
deps = [
"@com_google_absl//absl/hash",
],
)

objc_library(
Expand All @@ -132,16 +138,6 @@ objc_library(
hdrs = ["String.h"],
)

objc_library(
name = "SantaVnodeHash",
srcs = ["SantaVnodeHash.mm"],
hdrs = ["SantaVnodeHash.h"],
deps = [
":SantaCache",
":SantaVnode",
],
)

objc_library(
name = "CertificateHelpers",
srcs = ["CertificateHelpers.m"],
Expand Down
16 changes: 3 additions & 13 deletions Source/common/SantaCache.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,21 +26,11 @@
#include <cstring>

#include "Source/common/BranchPrediction.h"
#include "absl/hash/hash.h"

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"

/**
A type to specialize to help SantaCache with its hashing.

The default works for numeric types with a multiplicative hash
using a prime near to the golden ratio, per Knuth.
*/
template <typename T>
uint64_t SantaCacheHasher(T const &t) {
return (uint64_t)t * 11400714819323198549UL;
};

/**
A somewhat simple, concurrent linked-list hash table intended for use in IOKit
kernel extensions.
Expand All @@ -54,7 +44,7 @@ uint64_t SantaCacheHasher(T const &t) {
The number of buckets is calculated as `maximum_size` / `per_bucket`
rounded up to the next power of 2. Locking is done per-bucket.
*/
template <typename KeyT, typename ValueT>
template <typename KeyT, typename ValueT, class Hasher = absl::Hash<KeyT>>
class SantaCache {
public:
/**
Expand Down Expand Up @@ -359,7 +349,7 @@ class SantaCache {
Hash a key to determine which bucket it belongs in.
*/
inline uint64_t hash(KeyT input) const {
return SantaCacheHasher<KeyT>(input) % bucket_count_;
return Hasher{}(input) % bucket_count_;
}
};

Expand Down
14 changes: 5 additions & 9 deletions Source/common/SantaCacheTest.mm
Original file line number Diff line number Diff line change
Expand Up @@ -195,11 +195,6 @@ - (void)testDoubles {
XCTAssertEqual(sut.get(3.1459124), 0);
}

template <>
uint64_t SantaCacheHasher<std::string>(std::string const &s) {
return std::hash<std::string>{}(s);
}

- (void)testStrings {
auto sut = SantaCache<std::string, std::string>();

Expand Down Expand Up @@ -248,11 +243,12 @@ - (void)testCompareAndSwap {
bool operator==(const S &rhs) const {
return first_val == rhs.first_val && second_val == rhs.second_val;
}

template <typename H>
friend H AbslHashValue(H h, const S &v) {
return H::combine(std::move(h), v.first_val, v.second_val);
}
};
template <>
uint64_t SantaCacheHasher<S>(S const &s) {
return SantaCacheHasher<uint64_t>(s.first_val) ^ (SantaCacheHasher<uint64_t>(s.second_val) << 1);
}

- (void)testStructKeys {
auto sut = SantaCache<S, uint64_t>(10, 2);
Expand Down
9 changes: 9 additions & 0 deletions Source/common/SantaVnode.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@
#include <EndpointSecurity/EndpointSecurity.h>
#include <sys/types.h>

#ifdef __cplusplus
#include "absl/hash/hash.h"
#endif

// Struct to manage vnode IDs
typedef struct SantaVnode {
dev_t fsid;
Expand All @@ -38,6 +42,11 @@ typedef struct SantaVnode {
static inline SantaVnode VnodeForFile(const es_file_t *es_file) {
return VnodeForFile(es_file->stat);
}

template <typename H>
friend H AbslHashValue(H h, const SantaVnode &v) {
return H::combine(std::move(h), v.fsid, v.fileid);
}
#endif
} SantaVnode;

Expand Down
24 changes: 0 additions & 24 deletions Source/common/SantaVnodeHash.h

This file was deleted.

20 changes: 0 additions & 20 deletions Source/common/SantaVnodeHash.mm

This file was deleted.

4 changes: 0 additions & 4 deletions Source/santad/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,6 @@ objc_library(
"//Source/common:SNTRule",
"//Source/common:SantaCache",
"//Source/common:SantaVnode",
"//Source/common:SantaVnodeHash",
],
)

Expand Down Expand Up @@ -434,7 +433,6 @@ objc_library(
"//Source/common:SNTStrengthify",
"//Source/common:SantaCache",
"//Source/common:SantaVnode",
"//Source/common:SantaVnodeHash",
"//Source/common:String",
"@MOLCertificate",
"@MOLCodesignChecker",
Expand Down Expand Up @@ -474,7 +472,6 @@ objc_library(
"//Source/common:SNTMetricSet",
"//Source/common:SantaCache",
"//Source/common:SantaVnode",
"//Source/common:SantaVnodeHash",
],
)

Expand Down Expand Up @@ -541,7 +538,6 @@ objc_library(
":SNTDecisionCache",
"//Source/common:SantaCache",
"//Source/common:SantaVnode",
"//Source/common:SantaVnodeHash",
"//Source/common:String",
],
)
Expand Down
1 change: 0 additions & 1 deletion Source/santad/EventProviders/AuthResultCache.mm
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
#include <time.h>

#import "Source/common/SNTLogging.h"
#import "Source/common/SantaVnodeHash.h"
#include "Source/santad/EventProviders/EndpointSecurity/Client.h"

using santa::Client;
Expand Down
45 changes: 34 additions & 11 deletions Source/santad/EventProviders/SNTEndpointSecurityAuthorizer.mm
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,19 @@ - (NSString *)description {
}

- (void)processMessage:(const Message &)msg {
if (msg->event_type == ES_EVENT_TYPE_AUTH_PROC_SUSPEND_RESUME) {
[self.execController
validateSuspendResumeEvent:msg
postAction:^(bool allowed) {
es_auth_result_t authResult =
allowed ? ES_AUTH_RESULT_ALLOW : ES_AUTH_RESULT_DENY;
[self respondToMessage:msg
withAuthResult:authResult
cacheable:(authResult == ES_AUTH_RESULT_ALLOW)];
}];
return;
}

const es_file_t *targetFile = msg->event.exec.target->executable;

while (true) {
Expand Down Expand Up @@ -103,17 +116,26 @@ - (void)processMessage:(const Message &)msg {

- (void)handleMessage:(Message &&)esMsg
recordEventMetrics:(void (^)(EventDisposition))recordEventMetrics {
if (unlikely(esMsg->event_type != ES_EVENT_TYPE_AUTH_EXEC)) {
// This is a programming error
LOGE(@"Atteempting to authorize a non-exec event");
[NSException raise:@"Invalid event type"
format:@"Authorizing unexpected event type: %d", esMsg->event_type];
}

if (![self.execController synchronousShouldProcessExecEvent:esMsg]) {
[self postAction:SNTActionRespondDeny forMessage:esMsg];
recordEventMetrics(EventDisposition::kDropped);
return;
switch (esMsg->event_type) {
case ES_EVENT_TYPE_AUTH_EXEC:
if (![self.execController synchronousShouldProcessExecEvent:esMsg]) {
[self postAction:SNTActionRespondDeny forMessage:esMsg];
recordEventMetrics(EventDisposition::kDropped);
return;
}
break;
case ES_EVENT_TYPE_AUTH_PROC_SUSPEND_RESUME:
if (esMsg->event.proc_suspend_resume.type != ES_PROC_SUSPEND_RESUME_TYPE_RESUME) {
[self respondToMessage:esMsg withAuthResult:ES_AUTH_RESULT_ALLOW cacheable:YES];
recordEventMetrics(EventDisposition::kDropped);
return;
}
break;
default:
// This is a programming error
LOGE(@"Attempting to authorize a non-exec event");
[NSException raise:@"Invalid event type"
format:@"Authorizing unexpected event type: %d", esMsg->event_type];
}

[self processMessage:std::move(esMsg)
Expand Down Expand Up @@ -153,6 +175,7 @@ - (bool)postAction:(SNTAction)action forMessage:(const Message &)esMsg {
- (void)enable {
[super subscribeAndClearCache:{
ES_EVENT_TYPE_AUTH_EXEC,
ES_EVENT_TYPE_AUTH_PROC_SUSPEND_RESUME,
}];
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,8 @@ - (void)tearDown {

- (void)testEnable {
// Ensure the client subscribes to expected event types
std::set<es_event_type_t> expectedEventSubs{ES_EVENT_TYPE_AUTH_EXEC};
std::set<es_event_type_t> expectedEventSubs{ES_EVENT_TYPE_AUTH_EXEC,
ES_EVENT_TYPE_AUTH_PROC_SUSPEND_RESUME};
auto mockESApi = std::make_shared<MockEndpointSecurityAPI>();

id authClient =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,7 @@ - (bool)respondToMessage:(const Message &)msg
cacheable:(bool)cacheable {
if (msg->event_type == ES_EVENT_TYPE_AUTH_OPEN) {
return _esApi->RespondFlagsResult(
// For now, Santa is only concerned about alllowing all access or no
// For now, Santa is only concerned about allowing all access or no
// access, hence the flags being translated here to all or nothing based
// on the auth result. In the future it might be beneficial to expand the
// scope of Santa to enforce things like read-only access.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@
#import "Source/common/SNTStrengthify.h"
#include "Source/common/SantaCache.h"
#include "Source/common/SantaVnode.h"
#include "Source/common/SantaVnodeHash.h"
#include "Source/common/String.h"
#include "Source/santad/DataLayer/WatchItemPolicy.h"
#include "Source/santad/DataLayer/WatchItems.h"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@

#include "Source/common/SantaCache.h"
#import "Source/common/SantaVnode.h"
#include "Source/common/SantaVnodeHash.h"
#include "Source/common/String.h"

// These functions are exported by the Security framework, but are not included in headers
Expand Down
2 changes: 2 additions & 0 deletions Source/santad/Metrics.mm
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
static NSString *const kEventTypeAuthRemount = @"AuthRemount";
static NSString *const kEventTypeAuthRename = @"AuthRename";
static NSString *const kEventTypeAuthSignal = @"AuthSignal";
static NSString *const kEventTypeAuthProcSuspendResume = @"AuthProcSuspendResume";
static NSString *const kEventTypeAuthTruncate = @"AuthTruncate";
static NSString *const kEventTypeAuthUnlink = @"AuthUnlink";
static NSString *const kEventTypeNotifyClose = @"NotifyClose";
Expand Down Expand Up @@ -120,6 +121,7 @@
case ES_EVENT_TYPE_AUTH_REMOUNT: return kEventTypeAuthRemount;
case ES_EVENT_TYPE_AUTH_RENAME: return kEventTypeAuthRename;
case ES_EVENT_TYPE_AUTH_SIGNAL: return kEventTypeAuthSignal;
case ES_EVENT_TYPE_AUTH_PROC_SUSPEND_RESUME: return kEventTypeAuthProcSuspendResume;
case ES_EVENT_TYPE_AUTH_TRUNCATE: return kEventTypeAuthTruncate;
case ES_EVENT_TYPE_AUTH_UNLINK: return kEventTypeAuthUnlink;
case ES_EVENT_TYPE_NOTIFY_CLOSE: return kEventTypeNotifyClose;
Expand Down
3 changes: 3 additions & 0 deletions Source/santad/MetricsTest.mm
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

#include "Source/santad/Metrics.h"

#include <EndpointSecurity/ESTypes.h>
#include <EndpointSecurity/EndpointSecurity.h>
#import <Foundation/Foundation.h>
#import <OCMock/OCMock.h>
Expand Down Expand Up @@ -185,8 +186,10 @@ - (void)testEventTypeToString {
{ES_EVENT_TYPE_AUTH_KEXTLOAD, @"AuthKextload"},
{ES_EVENT_TYPE_AUTH_LINK, @"AuthLink"},
{ES_EVENT_TYPE_AUTH_MOUNT, @"AuthMount"},
{ES_EVENT_TYPE_AUTH_PROC_SUSPEND_RESUME, @"AuthProcSuspendResume"},
{ES_EVENT_TYPE_AUTH_REMOUNT, @"AuthRemount"},
{ES_EVENT_TYPE_AUTH_RENAME, @"AuthRename"},
{ES_EVENT_TYPE_AUTH_SIGNAL, @"AuthSignal"},
{ES_EVENT_TYPE_AUTH_TRUNCATE, @"AuthTruncate"},
{ES_EVENT_TYPE_AUTH_UNLINK, @"AuthUnlink"},
{ES_EVENT_TYPE_NOTIFY_CLOSE, @"NotifyClose"},
Expand Down
1 change: 0 additions & 1 deletion Source/santad/SNTDecisionCache.mm
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
#import "Source/common/SNTRule.h"
#include "Source/common/SantaCache.h"
#include "Source/common/SantaVnode.h"
#include "Source/common/SantaVnodeHash.h"
#import "Source/santad/DataLayer/SNTRuleTable.h"
#import "Source/santad/SNTDatabaseController.h"

Expand Down
11 changes: 11 additions & 0 deletions Source/santad/SNTExecutionController.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,16 @@ const static NSString *kBlockLongPath = @"BlockLongPath";
///
- (void)validateExecEvent:(const santa::Message &)esMsg postAction:(bool (^)(SNTAction))postAction;

///
/// Handles the logic of deciding whether to allow a pid_suspend/pid_resume through to a binary or
/// not, sends the response to the given `postAction` block.
///
/// @param message The message reveived from the EndpointSecurity event provider.
/// @param postAction The block invoked with the desired response result.
///
- (void)validateSuspendResumeEvent:(const santa::Message &)esMsg
postAction:(void (^)(bool))postAction;

///
/// Perform light, synchronous processing of the given event to decide whether or not the
/// event should undergo full processing. The checks done by this function MUST NOT block
Expand All @@ -88,4 +98,5 @@ const static NSString *kBlockLongPath = @"BlockLongPath";

- (void)updateEntitlementsPrefixFilter:(NSArray<NSString *> *)filter;
- (void)updateEntitlementsTeamIDFilter:(NSArray<NSString *> *)filter;

@end
Loading
Loading