Skip to content

Commit

Permalink
Set metrics when auth result cache is flushed.
Browse files Browse the repository at this point in the history
  • Loading branch information
mlw committed Apr 20, 2023
1 parent 95b9dbe commit 2795d12
Show file tree
Hide file tree
Showing 9 changed files with 99 additions and 25 deletions.
1 change: 1 addition & 0 deletions Source/santad/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,7 @@ objc_library(
":EndpointSecurityClient",
"//Source/common:SNTCommonEnums",
"//Source/common:SNTLogging",
"//Source/common:SNTMetricSet",
"//Source/common:SantaCache",
"//Source/common:SantaVnode",
"//Source/common:SantaVnodeHash",
Expand Down
10 changes: 8 additions & 2 deletions Source/santad/EventProviders/AuthResultCache.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include <memory>

#import "Source/common/SNTCommonEnums.h"
#import "Source/common/SNTMetricSet.h"
#include "Source/common/SantaCache.h"
#import "Source/common/SantaVnode.h"
#include "Source/santad/EventProviders/EndpointSecurity/EndpointSecurityAPI.h"
Expand All @@ -45,13 +46,17 @@ enum class FlushCacheReason {
class AuthResultCache {
public:
// Santa currently only flushes caches when new DENY rules are added, not
// ALLOW rules. This means this value should be low enough so that if a
// ALLOW rules. This means cache_deny_time_ms should be low enough so that if a
// previously denied binary is allowed, it can be re-executed by the user in a
// timely manner. But the value should be high enough to allow the cache to be
// effective in the event the binary is executed in rapid succession.
static std::unique_ptr<AuthResultCache> Create(
std::shared_ptr<santa::santad::event_providers::endpoint_security::EndpointSecurityAPI> esapi,
SNTMetricSet *metric_set, uint64_t cache_deny_time_ms = 1500);

AuthResultCache(
std::shared_ptr<santa::santad::event_providers::endpoint_security::EndpointSecurityAPI> esapi,
uint64_t cache_deny_time_ms = 1500);
SNTMetricCounter *flush_count, uint64_t cache_deny_time_ms = 1500);
virtual ~AuthResultCache();

AuthResultCache(AuthResultCache &&other) = delete;
Expand All @@ -75,6 +80,7 @@ class AuthResultCache {
SantaCache<SantaVnode, uint64_t> *nonroot_cache_;

std::shared_ptr<santa::santad::event_providers::endpoint_security::EndpointSecurityAPI> esapi_;
SNTMetricCounter *flush_count_;
uint64_t root_devno_;
uint64_t cache_deny_time_ns_;
dispatch_queue_t q_;
Expand Down
40 changes: 38 additions & 2 deletions Source/santad/EventProviders/AuthResultCache.mm
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,13 @@
using santa::santad::event_providers::endpoint_security::Client;
using santa::santad::event_providers::endpoint_security::EndpointSecurityAPI;

static NSString *const kFlushCacheReasonClientModeChanged = @"ClientModeChanged";
static NSString *const kFlushCacheReasonPathRegexChanged = @"PathRegexChanged";
static NSString *const kFlushCacheReasonRulesChanged = @"RulesChanged";
static NSString *const kFlushCacheReasonStaticRulesChanged = @"StaticRulesChanged";
static NSString *const kFlushCacheReasonExplicitCommand = @"ExplicitCommand";
static NSString *const kFlushCacheReasonFilesystemUnmounted = @"FilesystemUnmounted";

namespace santa::santad::event_providers {

static inline uint64_t GetCurrentUptime() {
Expand All @@ -44,9 +51,36 @@ static inline uint64_t TimestampFromCachedValue(uint64_t cachedValue) {
return (cachedValue & ~(0xFF00000000000000));
}

NSString *const FlushCacheReasonToString(FlushCacheReason reason) {
switch (reason) {
case FlushCacheReason::kClientModeChanged: return kFlushCacheReasonClientModeChanged;
case FlushCacheReason::kPathRegexChanged: return kFlushCacheReasonPathRegexChanged;
case FlushCacheReason::kRulesChanged: return kFlushCacheReasonRulesChanged;
case FlushCacheReason::kStaticRulesChanged: return kFlushCacheReasonStaticRulesChanged;
case FlushCacheReason::kExplicitCommand: return kFlushCacheReasonExplicitCommand;
case FlushCacheReason::kFilesystemUnmounted: return kFlushCacheReasonFilesystemUnmounted;
default:
[NSException raise:@"Invalid reason" format:@"Unknown reason value: %d", reason];
return nil;
}
}

std::unique_ptr<AuthResultCache> AuthResultCache::Create(std::shared_ptr<EndpointSecurityAPI> esapi,
SNTMetricSet *metric_set,
uint64_t cache_deny_time_ms) {
SNTMetricCounter *flush_count =
[metric_set counterWithName:@"/santa/flush_count"
fieldNames:@[ @"Reason" ]
helpText:@"Count of times the auth result cache is flushed by reason"];

return std::make_unique<AuthResultCache>(esapi, flush_count, cache_deny_time_ms);
}

AuthResultCache::AuthResultCache(std::shared_ptr<EndpointSecurityAPI> esapi,
uint64_t cache_deny_time_ms)
: esapi_(esapi), cache_deny_time_ns_(cache_deny_time_ms * NSEC_PER_MSEC) {
SNTMetricCounter *flush_count, uint64_t cache_deny_time_ms)
: esapi_(esapi),
flush_count_(flush_count),
cache_deny_time_ns_(cache_deny_time_ms * NSEC_PER_MSEC) {
root_cache_ = new SantaCache<SantaVnode, uint64_t>();
nonroot_cache_ = new SantaCache<SantaVnode, uint64_t>();

Expand Down Expand Up @@ -134,6 +168,8 @@ static inline uint64_t TimestampFromCachedValue(uint64_t cachedValue) {
shared_esapi->ClearCache(Client());
});
}

[flush_count_ incrementForFieldValues:@[ FlushCacheReasonToString(reason) ]];
}

NSArray<NSNumber *> *AuthResultCache::CacheCounts() {
Expand Down
33 changes: 28 additions & 5 deletions Source/santad/EventProviders/AuthResultCacheTest.mm
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@
using santa::santad::event_providers::FlushCacheMode;
using santa::santad::event_providers::FlushCacheReason;

namespace santa::santad::event_providers {
extern NSString *const FlushCacheReasonToString(FlushCacheReason reason);
}

using santa::santad::event_providers::FlushCacheReasonToString;

// Grab the st_dev number of the root volume to match the root cache
static uint64_t RootDevno() {
static dispatch_once_t once_token;
Expand Down Expand Up @@ -67,14 +73,14 @@ @implementation AuthResultCacheTest

- (void)testEmptyCacheExpectedNumberOfCacheCounts {
auto esapi = std::make_shared<MockEndpointSecurityAPI>();
auto cache = std::make_shared<AuthResultCache>(esapi);
std::shared_ptr<AuthResultCache> cache = AuthResultCache::Create(esapi, nil);

AssertCacheCounts(cache, 0, 0);
}

- (void)testBasicOperation {
auto esapi = std::make_shared<MockEndpointSecurityAPI>();
auto cache = std::make_shared<AuthResultCache>(esapi);
std::shared_ptr<AuthResultCache> cache = AuthResultCache::Create(esapi, nil);

es_file_t rootFile = MakeCacheableFile(RootDevno(), 111);
es_file_t nonrootFile = MakeCacheableFile(RootDevno() + 123, 222);
Expand Down Expand Up @@ -111,7 +117,7 @@ - (void)testBasicOperation {

- (void)testFlushCache {
auto mockESApi = std::make_shared<MockEndpointSecurityAPI>();
auto cache = std::make_shared<AuthResultCache>(mockESApi);
std::shared_ptr<AuthResultCache> cache = AuthResultCache::Create(mockESApi, nil);

es_file_t rootFile = MakeCacheableFile(RootDevno(), 111);
es_file_t nonrootFile = MakeCacheableFile(RootDevno() + 123, 111);
Expand Down Expand Up @@ -152,7 +158,7 @@ - (void)testFlushCache {

- (void)testCacheStateMachine {
auto mockESApi = std::make_shared<MockEndpointSecurityAPI>();
auto cache = std::make_shared<AuthResultCache>(mockESApi);
std::shared_ptr<AuthResultCache> cache = AuthResultCache::Create(mockESApi, nil);

es_file_t rootFile = MakeCacheableFile(RootDevno(), 111);

Expand Down Expand Up @@ -194,7 +200,7 @@ - (void)testCacheExpiry {
auto mockESApi = std::make_shared<MockEndpointSecurityAPI>();
// Create a cache with a lowered cache expiry value
uint64_t expiryMS = 250;
auto cache = std::make_shared<AuthResultCache>(mockESApi, expiryMS);
std::shared_ptr<AuthResultCache> cache = AuthResultCache::Create(mockESApi, nil, expiryMS);

es_file_t rootFile = MakeCacheableFile(RootDevno(), 111);

Expand All @@ -216,4 +222,21 @@ - (void)testCacheExpiry {
AssertCacheCounts(cache, 0, 0);
}

- (void)testFlushCacheReasonToString {
std::map<FlushCacheReason, NSString *> reasonToString = {
{FlushCacheReason::kClientModeChanged, @"ClientModeChanged"},
{FlushCacheReason::kPathRegexChanged, @"PathRegexChanged"},
{FlushCacheReason::kRulesChanged, @"RulesChanged"},
{FlushCacheReason::kStaticRulesChanged, @"StaticRulesChanged"},
{FlushCacheReason::kExplicitCommand, @"ExplicitCommand"},
{FlushCacheReason::kFilesystemUnmounted, @"FilesystemUnmounted"},
};

for (const auto &kv : reasonToString) {
XCTAssertEqualObjects(FlushCacheReasonToString(kv.first), kv.second);
}

XCTAssertThrows(FlushCacheReasonToString((FlushCacheReason)12345));
}

@end
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ - (void)testProcessMessageWaitThenAllow {
mockESApi->SetExpectationsESNewClient();
mockESApi->SetExpectationsRetainReleaseMessage();

auto mockAuthCache = std::make_shared<MockAuthResultCache>(nullptr);
auto mockAuthCache = std::make_shared<MockAuthResultCache>(nullptr, nil);
EXPECT_CALL(*mockAuthCache, CheckCache)
.WillOnce(testing::Return(SNTActionRequestBinary))
.WillOnce(testing::Return(SNTActionRequestBinary))
Expand Down Expand Up @@ -301,7 +301,7 @@ - (void)testPostAction {
mockESApi->SetExpectationsESNewClient();
mockESApi->SetExpectationsRetainReleaseMessage();

auto mockAuthCache = std::make_shared<MockAuthResultCache>(nullptr);
auto mockAuthCache = std::make_shared<MockAuthResultCache>(nullptr, nil);
EXPECT_CALL(*mockAuthCache, AddToCache(&execFile, SNTActionRespondAllowCompiler))
.WillOnce(testing::Return(true));
EXPECT_CALL(*mockAuthCache, AddToCache(&execFile, SNTActionRespondAllow))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,7 @@ - (void)testNotifyUnmountFlushesCache {
mockESApi->SetExpectationsESNewClient();
mockESApi->SetExpectationsRetainReleaseMessage();

auto mockAuthCache = std::make_shared<MockAuthResultCache>(nullptr);
auto mockAuthCache = std::make_shared<MockAuthResultCache>(nullptr, nil);
EXPECT_CALL(*mockAuthCache, FlushCache);

SNTEndpointSecurityDeviceManager *deviceManager =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ - (void)testHandleMessage {
auto mockEnricher = std::make_shared<MockEnricher>();
EXPECT_CALL(*mockEnricher, Enrich).WillOnce(testing::Return(enrichedMsg));

auto mockAuthCache = std::make_shared<MockAuthResultCache>(nullptr);
auto mockAuthCache = std::make_shared<MockAuthResultCache>(nullptr, nil);
EXPECT_CALL(*mockAuthCache, RemoveFromCache(&targetFile)).Times(1);

dispatch_semaphore_t semaMetrics = dispatch_semaphore_create(0);
Expand Down
2 changes: 2 additions & 0 deletions Source/santad/SantadDeps.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ class SantadDeps {
std::unique_ptr<santa::santad::logs::endpoint_security::Logger> logger,
std::shared_ptr<santa::santad::Metrics> metrics,
std::shared_ptr<santa::santad::data_layer::WatchItems> watch_items,
std::shared_ptr<santa::santad::event_providers::AuthResultCache>
auth_result_cache,
MOLXPCConnection *control_connection,
SNTCompilerController *compiler_controller,
SNTNotificationQueue *notifier_queue, SNTSyncdQueue *syncd_queue,
Expand Down
30 changes: 18 additions & 12 deletions Source/santad/SantadDeps.mm
Original file line number Diff line number Diff line change
Expand Up @@ -135,25 +135,31 @@
exit(EXIT_FAILURE);
}

return std::make_unique<SantadDeps>(
esapi, std::move(logger), std::move(metrics), std::move(watch_items), control_connection,
compiler_controller, notifier_queue, syncd_queue, exec_controller, prefix_tree);
std::shared_ptr<::AuthResultCache> auth_result_cache = AuthResultCache::Create(esapi, metric_set);
if (!auth_result_cache) {
LOGE(@"Failed to create auth result cache");
exit(EXIT_FAILURE);
}

return std::make_unique<SantadDeps>(esapi, std::move(logger), std::move(metrics),
std::move(watch_items), std::move(auth_result_cache),
control_connection, compiler_controller, notifier_queue,
syncd_queue, exec_controller, prefix_tree);
}

SantadDeps::SantadDeps(std::shared_ptr<EndpointSecurityAPI> esapi, std::unique_ptr<::Logger> logger,
std::shared_ptr<::Metrics> metrics,
std::shared_ptr<::WatchItems> watch_items,
MOLXPCConnection *control_connection,
SNTCompilerController *compiler_controller,
SNTNotificationQueue *notifier_queue, SNTSyncdQueue *syncd_queue,
SNTExecutionController *exec_controller,
std::shared_ptr<::PrefixTree<Unit>> prefix_tree)
SantadDeps::SantadDeps(
std::shared_ptr<EndpointSecurityAPI> esapi, std::unique_ptr<::Logger> logger,
std::shared_ptr<::Metrics> metrics, std::shared_ptr<::WatchItems> watch_items,
std::shared_ptr<santa::santad::event_providers::AuthResultCache> auth_result_cache,
MOLXPCConnection *control_connection, SNTCompilerController *compiler_controller,
SNTNotificationQueue *notifier_queue, SNTSyncdQueue *syncd_queue,
SNTExecutionController *exec_controller, std::shared_ptr<::PrefixTree<Unit>> prefix_tree)
: esapi_(std::move(esapi)),
logger_(std::move(logger)),
metrics_(std::move(metrics)),
watch_items_(std::move(watch_items)),
enricher_(std::make_shared<::Enricher>()),
auth_result_cache_(std::make_shared<::AuthResultCache>(esapi_)),
auth_result_cache_(std::move(auth_result_cache)),
control_connection_(control_connection),
compiler_controller_(compiler_controller),
notifier_queue_(notifier_queue),
Expand Down

0 comments on commit 2795d12

Please sign in to comment.