mirror of
https://github.com/google/santa.git
synced 2026-04-24 03:00:12 -04:00
santad: Log file changes, use prefix trees (#398)
This commit is contained in:
2
BUILD
2
BUILD
@@ -147,8 +147,8 @@ test_suite(
|
||||
name = "unit_tests",
|
||||
tests = [
|
||||
"//Source/common:SNTFileInfoTest",
|
||||
"//Source/common:SNTPrefixTreeTest",
|
||||
"//Source/santa_driver:SantaCacheTest",
|
||||
"//Source/santa_driver:SantaPrefixTreeTest",
|
||||
"//Source/santactl:SNTCommandFileInfoTest",
|
||||
"//Source/santactl:SNTCommandSyncTest",
|
||||
"//Source/santad:SNTEventTableTest",
|
||||
|
||||
@@ -7,12 +7,13 @@
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
0D9F577C2342650F005D9AA8 /* SNTPrefixTree.cc in Sources */ = {isa = PBXBuildFile; fileRef = C7658B022322B84F00F36578 /* SNTPrefixTree.cc */; };
|
||||
59502195B2982225D3706DCE /* libPods-santabundleservice.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 2A55D73A235850B9FA991865 /* libPods-santabundleservice.a */; };
|
||||
AD3736AF78C41A962C26D429 /* libPods-Santa.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C3E743944A9D77423AA1534 /* libPods-Santa.a */; };
|
||||
B5AE6BB811766CA492133559 /* libPods-santad.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3700D40B536CA7F626B76156 /* libPods-santad.a */; };
|
||||
C71E472F22F0F97B00921CD9 /* santad in CopyFiles */ = {isa = PBXBuildFile; fileRef = C779C4E622F0F51400EE2541 /* santad */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
|
||||
C71E473122F0FAA100921CD9 /* com.google.santa.daemon.systemextension in CopyFiles */ = {isa = PBXBuildFile; fileRef = C7A8308022F0F81F00F856AC /* com.google.santa.daemon.systemextension */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
C72ED2B62324962400255555 /* SNTEndpointSecurityManager.m in Sources */ = {isa = PBXBuildFile; fileRef = C72ED2B52324962400255555 /* SNTEndpointSecurityManager.m */; };
|
||||
C72ED2B62324962400255555 /* SNTEndpointSecurityManager.mm in Sources */ = {isa = PBXBuildFile; fileRef = C72ED2B52324962400255555 /* SNTEndpointSecurityManager.mm */; };
|
||||
C72ED2B82324A2FA00255555 /* libEndpointSecurity.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = C72ED2B72324A2FA00255555 /* libEndpointSecurity.tbd */; };
|
||||
C72ED2BC232584C100255555 /* libbsm.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = C72ED2BB232584C100255555 /* libbsm.tbd */; };
|
||||
C7658B142322BDD500F36578 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = C7658AEA2322B84F00F36578 /* main.m */; };
|
||||
@@ -104,7 +105,7 @@
|
||||
C7D35DE42322C99B000C5EB4 /* SantaDecisionManager.cc in Sources */ = {isa = PBXBuildFile; fileRef = C7658B002322B84F00F36578 /* SantaDecisionManager.cc */; };
|
||||
C7D35DE52322C99E000C5EB4 /* SantaDriver.cc in Sources */ = {isa = PBXBuildFile; fileRef = C7658AFF2322B84F00F36578 /* SantaDriver.cc */; };
|
||||
C7D35DE62322C9A1000C5EB4 /* SantaDriverClient.cc in Sources */ = {isa = PBXBuildFile; fileRef = C7658AFA2322B84F00F36578 /* SantaDriverClient.cc */; };
|
||||
C7D35DE72322C9A4000C5EB4 /* SantaPrefixTree.cc in Sources */ = {isa = PBXBuildFile; fileRef = C7658B022322B84F00F36578 /* SantaPrefixTree.cc */; };
|
||||
C7D35DE72322C9A4000C5EB4 /* SNTPrefixTree.cc in Sources */ = {isa = PBXBuildFile; fileRef = C7658B022322B84F00F36578 /* SNTPrefixTree.cc */; };
|
||||
C7F5C1AE233E72CC00A3F7FD /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = C7658AF62322B84F00F36578 /* main.m */; };
|
||||
C7F5C1AF233E72CF00A3F7FD /* SNTBundleService.m in Sources */ = {isa = PBXBuildFile; fileRef = C7658AF22322B84F00F36578 /* SNTBundleService.m */; };
|
||||
C7F5C1B0233E735E00A3F7FD /* santabundleservice in CopyFiles */ = {isa = PBXBuildFile; fileRef = C7F5C1A7233E72BC00A3F7FD /* santabundleservice */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
|
||||
@@ -196,7 +197,7 @@
|
||||
C05543B3701F50CA798B4B11 /* Pods-sysx.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-sysx.release.xcconfig"; path = "Target Support Files/Pods-sysx/Pods-sysx.release.xcconfig"; sourceTree = "<group>"; };
|
||||
C72ED2B3232495CC00255555 /* SNTEventProvider.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SNTEventProvider.h; sourceTree = "<group>"; };
|
||||
C72ED2B42324962400255555 /* SNTEndpointSecurityManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SNTEndpointSecurityManager.h; sourceTree = "<group>"; };
|
||||
C72ED2B52324962400255555 /* SNTEndpointSecurityManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SNTEndpointSecurityManager.m; sourceTree = "<group>"; };
|
||||
C72ED2B52324962400255555 /* SNTEndpointSecurityManager.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = SNTEndpointSecurityManager.mm; sourceTree = "<group>"; };
|
||||
C72ED2B72324A2FA00255555 /* libEndpointSecurity.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libEndpointSecurity.tbd; path = usr/lib/libEndpointSecurity.tbd; sourceTree = SDKROOT; };
|
||||
C72ED2B9232584AA00255555 /* libauditd.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libauditd.tbd; path = usr/lib/libauditd.tbd; sourceTree = SDKROOT; };
|
||||
C72ED2BB232584C100255555 /* libbsm.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libbsm.tbd; path = usr/lib/libbsm.tbd; sourceTree = SDKROOT; };
|
||||
@@ -344,13 +345,13 @@
|
||||
C7658AFB2322B84F00F36578 /* SantaCacheTest.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = SantaCacheTest.mm; sourceTree = "<group>"; };
|
||||
C7658AFC2322B84F00F36578 /* SantaCache.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SantaCache.h; sourceTree = "<group>"; };
|
||||
C7658AFD2322B84F00F36578 /* SantaDriverClient.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SantaDriverClient.h; sourceTree = "<group>"; };
|
||||
C7658AFE2322B84F00F36578 /* SantaPrefixTreeTest.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = SantaPrefixTreeTest.mm; sourceTree = "<group>"; };
|
||||
C7658AFE2322B84F00F36578 /* SNTPrefixTreeTest.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = SNTPrefixTreeTest.mm; sourceTree = "<group>"; };
|
||||
C7658AFF2322B84F00F36578 /* SantaDriver.cc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = SantaDriver.cc; sourceTree = "<group>"; };
|
||||
C7658B002322B84F00F36578 /* SantaDecisionManager.cc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = SantaDecisionManager.cc; sourceTree = "<group>"; };
|
||||
C7658B012322B84F00F36578 /* kernel_tests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = kernel_tests.mm; sourceTree = "<group>"; };
|
||||
C7658B022322B84F00F36578 /* SantaPrefixTree.cc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = SantaPrefixTree.cc; sourceTree = "<group>"; };
|
||||
C7658B022322B84F00F36578 /* SNTPrefixTree.cc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = SNTPrefixTree.cc; sourceTree = "<group>"; };
|
||||
C7658B032322B84F00F36578 /* BUILD */ = {isa = PBXFileReference; lastKnownFileType = text; path = BUILD; sourceTree = "<group>"; };
|
||||
C7658B042322B84F00F36578 /* SantaPrefixTree.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SantaPrefixTree.h; sourceTree = "<group>"; };
|
||||
C7658B042322B84F00F36578 /* SNTPrefixTree.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SNTPrefixTree.h; sourceTree = "<group>"; };
|
||||
C7658B052322B84F00F36578 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
C7658B062322B84F00F36578 /* SantaDriver.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SantaDriver.h; sourceTree = "<group>"; };
|
||||
C7658B072322B84F00F36578 /* SantaDecisionManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SantaDecisionManager.h; sourceTree = "<group>"; };
|
||||
@@ -430,7 +431,7 @@
|
||||
C7658A632322B84F00F36578 /* SNTDriverManager.h */,
|
||||
C7658A742322B84F00F36578 /* SNTDriverManager.m */,
|
||||
C72ED2B42324962400255555 /* SNTEndpointSecurityManager.h */,
|
||||
C72ED2B52324962400255555 /* SNTEndpointSecurityManager.m */,
|
||||
C72ED2B52324962400255555 /* SNTEndpointSecurityManager.mm */,
|
||||
C72ED2B3232495CC00255555 /* SNTEventProvider.h */,
|
||||
);
|
||||
path = EventProviders;
|
||||
@@ -608,6 +609,9 @@
|
||||
C7658ACE2322B84F00F36578 /* SNTKernelCommon.h */,
|
||||
C7658ACB2322B84F00F36578 /* SNTLogging.h */,
|
||||
C7658AD82322B84F00F36578 /* SNTLogging.m */,
|
||||
C7658B022322B84F00F36578 /* SNTPrefixTree.cc */,
|
||||
C7658B042322B84F00F36578 /* SNTPrefixTree.h */,
|
||||
C7658AFE2322B84F00F36578 /* SNTPrefixTreeTest.mm */,
|
||||
C7658ADB2322B84F00F36578 /* SNTRule.h */,
|
||||
C7658AC82322B84F00F36578 /* SNTRule.m */,
|
||||
C7658AC92322B84F00F36578 /* SNTStoredEvent.h */,
|
||||
@@ -743,9 +747,6 @@
|
||||
C7658B062322B84F00F36578 /* SantaDriver.h */,
|
||||
C7658AFA2322B84F00F36578 /* SantaDriverClient.cc */,
|
||||
C7658AFD2322B84F00F36578 /* SantaDriverClient.h */,
|
||||
C7658B022322B84F00F36578 /* SantaPrefixTree.cc */,
|
||||
C7658B042322B84F00F36578 /* SantaPrefixTree.h */,
|
||||
C7658AFE2322B84F00F36578 /* SantaPrefixTreeTest.mm */,
|
||||
);
|
||||
path = santa_driver;
|
||||
sourceTree = "<group>";
|
||||
@@ -1195,6 +1196,7 @@
|
||||
C7658B332322C08B00F36578 /* SNTRule.m in Sources */,
|
||||
C7658B382322C0B400F36578 /* SNTXPCSyncdInterface.m in Sources */,
|
||||
C7658B1D2322BFFA00F36578 /* main.m in Sources */,
|
||||
0D9F577C2342650F005D9AA8 /* SNTPrefixTree.cc in Sources */,
|
||||
C7658B282322C02300F36578 /* SNTDriverManager.m in Sources */,
|
||||
C7658B372322C0B000F36578 /* SNTXPCNotifierInterface.m in Sources */,
|
||||
C7658B312322C08000F36578 /* SNTLogging.m in Sources */,
|
||||
@@ -1218,7 +1220,7 @@
|
||||
C7658B212322C00B00F36578 /* SNTEventLog.m in Sources */,
|
||||
C7658B2E2322C06800F36578 /* SNTCachedDecision.m in Sources */,
|
||||
C7658B302322C07500F36578 /* SNTFileInfo.m in Sources */,
|
||||
C72ED2B62324962400255555 /* SNTEndpointSecurityManager.m in Sources */,
|
||||
C72ED2B62324962400255555 /* SNTEndpointSecurityManager.mm in Sources */,
|
||||
C7658B352322C0A000F36578 /* SNTXPCBundleServiceInterface.m in Sources */,
|
||||
C7658B272322C02000F36578 /* SNTDatabaseController.m in Sources */,
|
||||
C7658B222322C00E00F36578 /* SNTFileEventLog.m in Sources */,
|
||||
@@ -1238,7 +1240,7 @@
|
||||
files = (
|
||||
C7D35DE52322C99E000C5EB4 /* SantaDriver.cc in Sources */,
|
||||
C7D35DE62322C9A1000C5EB4 /* SantaDriverClient.cc in Sources */,
|
||||
C7D35DE72322C9A4000C5EB4 /* SantaPrefixTree.cc in Sources */,
|
||||
C7D35DE72322C9A4000C5EB4 /* SNTPrefixTree.cc in Sources */,
|
||||
C7D35DE42322C99B000C5EB4 /* SantaDecisionManager.cc in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
|
||||
@@ -84,6 +84,13 @@ objc_library(
|
||||
hdrs = ["SNTLogging.h"],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "SNTPrefixTree",
|
||||
srcs = ["SNTPrefixTree.cc"],
|
||||
hdrs = ["SNTPrefixTree.h"],
|
||||
copts = ["-std=c++11"],
|
||||
)
|
||||
|
||||
objc_library(
|
||||
name = "SNTRule",
|
||||
srcs = ["SNTRule.m"],
|
||||
@@ -182,3 +189,9 @@ santa_unit_test(
|
||||
]),
|
||||
deps = [":SNTFileInfo"],
|
||||
)
|
||||
|
||||
santa_unit_test(
|
||||
name = "SNTPrefixTreeTest",
|
||||
srcs = ["SNTPrefixTreeTest.mm"],
|
||||
deps = ["SNTPrefixTree"],
|
||||
)
|
||||
|
||||
@@ -126,6 +126,9 @@ typedef struct {
|
||||
char pname[MAXPATHLEN];
|
||||
// For messages that originate from EndpointSecurity, this points to a copy of the message.
|
||||
void *es_message;
|
||||
|
||||
// For messages that originate from EndpointSecurity, this points to an NSArray of the arguments.
|
||||
void *args_array;
|
||||
} santa_message_t;
|
||||
|
||||
// Used for the kSantaUserClientCacheBucketCount request.
|
||||
|
||||
@@ -34,6 +34,10 @@
|
||||
|
||||
#else // KERNEL
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
typedef enum : NSUInteger {
|
||||
@@ -60,6 +64,10 @@ void logMessage(LogLevel level, FILE *destination, NSString *format, ...)
|
||||
#define LOGW(logFormat, ...) logMessage(LOG_LEVEL_WARN, stderr, logFormat, ##__VA_ARGS__)
|
||||
#define LOGE(logFormat, ...) logMessage(LOG_LEVEL_ERROR, stderr, logFormat, ##__VA_ARGS__)
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern C
|
||||
#endif
|
||||
|
||||
#endif // KERNEL
|
||||
|
||||
#endif // SANTA__COMMON__LOGGING_H
|
||||
|
||||
@@ -12,55 +12,51 @@
|
||||
/// See the License for the specific language governing permissions and
|
||||
/// limitations under the License.
|
||||
|
||||
#include "Source/santa_driver/SantaPrefixTree.h"
|
||||
#include "Source/common/SNTPrefixTree.h"
|
||||
|
||||
#ifdef KERNEL
|
||||
#include <libkern/locks.h>
|
||||
|
||||
#include "Source/common/SNTLogging.h"
|
||||
|
||||
#else
|
||||
|
||||
#include <mutex>
|
||||
#include <string.h>
|
||||
|
||||
#define LOGD(format, ...) // NOP
|
||||
#define LOGE(format, ...) // NOP
|
||||
|
||||
#define lck_grp_attr_alloc_init() nullptr
|
||||
#define lck_grp_alloc_init(name, attr) nullptr
|
||||
#define lck_attr_alloc_init() nullptr
|
||||
#define lck_rw_lock_shared(l) pthread_rwlock_rdlock(&l)
|
||||
#define lck_rw_unlock_shared(l) pthread_rwlock_unlock(&l)
|
||||
#define lck_rw_lock_exclusive(l) pthread_rwlock_wrlock(&l)
|
||||
#define lck_rw_unlock_exclusive(l) pthread_rwlock_unlock(&l)
|
||||
|
||||
#define lck_rw_alloc_init(g, a) new std::shared_mutex
|
||||
#define lck_mtx_alloc_init(g, a) new std::mutex
|
||||
|
||||
#define lck_attr_free(attr) // NOP
|
||||
#define lck_grp_free(grp) // NOP
|
||||
#define lck_grp_attr_free(grp_attr) // NOP
|
||||
|
||||
#define lck_rw_lock_shared(l) l->lock_shared()
|
||||
#define lck_rw_unlock_shared(l) l->unlock_shared()
|
||||
#define lck_rw_lock_exclusive(l) l->lock()
|
||||
#define lck_rw_unlock_exclusive(l) l->unlock()
|
||||
|
||||
#define lck_rw_lock_shared_to_exclusive(l) ({ l->unlock_shared(); false; })
|
||||
#define lck_rw_lock_exclusive_to_shared(l) l->unlock(); l->lock_shared()
|
||||
#define lck_rw_lock_shared_to_exclusive(l) ({ pthread_rwlock_unlock(&l); false; })
|
||||
#define lck_rw_lock_exclusive_to_shared(l) ({ pthread_rwlock_unlock(&l); pthread_rwlock_rdlock(&l); })
|
||||
|
||||
#define lck_mtx_lock(l) l->lock()
|
||||
#define lck_mtx_unlock(l) l->unlock()
|
||||
#endif // KERNEL
|
||||
|
||||
SantaPrefixTree::SantaPrefixTree(uint32_t max_nodes) {
|
||||
SNTPrefixTree::SNTPrefixTree(uint32_t max_nodes) {
|
||||
root_ = new SantaPrefixNode();
|
||||
node_count_ = 0;
|
||||
max_nodes_ = max_nodes;
|
||||
|
||||
#ifdef KERNEL
|
||||
spt_lock_grp_attr_ = lck_grp_attr_alloc_init();
|
||||
spt_lock_grp_ = lck_grp_alloc_init("santa-prefix-tree-lock", spt_lock_grp_attr_);
|
||||
spt_lock_attr_ = lck_attr_alloc_init();
|
||||
|
||||
spt_lock_ = lck_rw_alloc_init(spt_lock_grp_, spt_lock_attr_);
|
||||
spt_add_lock_ = lck_mtx_alloc_init(spt_lock_grp_, spt_lock_attr_);
|
||||
#else
|
||||
pthread_rwlock_init(&spt_lock_, nullptr);
|
||||
spt_add_lock_ = new std::mutex;
|
||||
#endif
|
||||
}
|
||||
|
||||
IOReturn SantaPrefixTree::AddPrefix(const char *prefix, uint64_t *node_count) {
|
||||
IOReturn SNTPrefixTree::AddPrefix(const char *prefix, uint64_t *node_count) {
|
||||
// Serialize requests to AddPrefix. Otherwise one AddPrefix thread could overwrite whole
|
||||
// branches of another. HasPrefix is still free to read the tree, until AddPrefix needs to
|
||||
// modify it.
|
||||
@@ -156,7 +152,7 @@ IOReturn SantaPrefixTree::AddPrefix(const char *prefix, uint64_t *node_count) {
|
||||
return kIOReturnSuccess;
|
||||
}
|
||||
|
||||
bool SantaPrefixTree::HasPrefix(const char *string) {
|
||||
bool SNTPrefixTree::HasPrefix(const char *string) {
|
||||
lck_rw_lock_shared(spt_lock_);
|
||||
|
||||
auto found = false;
|
||||
@@ -184,7 +180,7 @@ bool SantaPrefixTree::HasPrefix(const char *string) {
|
||||
return found;
|
||||
}
|
||||
|
||||
void SantaPrefixTree::Reset() {
|
||||
void SNTPrefixTree::Reset() {
|
||||
lck_rw_lock_exclusive(spt_lock_);
|
||||
|
||||
PruneNode(root_);
|
||||
@@ -194,7 +190,7 @@ void SantaPrefixTree::Reset() {
|
||||
lck_rw_unlock_exclusive(spt_lock_);
|
||||
}
|
||||
|
||||
void SantaPrefixTree::PruneNode(SantaPrefixNode *target) {
|
||||
void SNTPrefixTree::PruneNode(SantaPrefixNode *target) {
|
||||
if (!target) return;
|
||||
|
||||
// For deep trees, a recursive approach will generate too many stack frames. Make a "stack"
|
||||
@@ -226,13 +222,13 @@ void SantaPrefixTree::PruneNode(SantaPrefixNode *target) {
|
||||
delete[] stack;
|
||||
}
|
||||
|
||||
SantaPrefixTree::~SantaPrefixTree() {
|
||||
SNTPrefixTree::~SNTPrefixTree() {
|
||||
lck_rw_lock_exclusive(spt_lock_);
|
||||
PruneNode(root_);
|
||||
root_ = nullptr;
|
||||
lck_rw_unlock_exclusive(spt_lock_);
|
||||
|
||||
#ifdef KERNEL
|
||||
#ifdef KERNEL
|
||||
if (spt_lock_) {
|
||||
lck_rw_free(spt_lock_, spt_lock_grp_);
|
||||
spt_lock_ = nullptr;
|
||||
@@ -242,7 +238,6 @@ SantaPrefixTree::~SantaPrefixTree() {
|
||||
lck_mtx_free(spt_add_lock_, spt_lock_grp_);
|
||||
spt_add_lock_ = nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (spt_lock_attr_) {
|
||||
lck_attr_free(spt_lock_attr_);
|
||||
@@ -258,4 +253,7 @@ SantaPrefixTree::~SantaPrefixTree() {
|
||||
lck_grp_attr_free(spt_lock_grp_attr_);
|
||||
spt_lock_grp_attr_ = nullptr;
|
||||
}
|
||||
#else
|
||||
pthread_rwlock_destroy(&spt_lock_);
|
||||
#endif
|
||||
}
|
||||
@@ -22,16 +22,16 @@
|
||||
#include <libkern/locks.h>
|
||||
#else
|
||||
// Support for unit testing.
|
||||
// Requires c++17 / macOS 10.12.
|
||||
// TODO(bur): Handle warnings from bumping target version of the tests to 10.12.
|
||||
#include <shared_mutex>
|
||||
#include <mutex>
|
||||
#include <pthread.h>
|
||||
#include <stdint.h>
|
||||
#endif // KERNEL
|
||||
|
||||
///
|
||||
/// SantaPrefixTree is a simple prefix tree implementation.
|
||||
/// Operations are thread safe.
|
||||
///
|
||||
class SantaPrefixTree {
|
||||
class SNTPrefixTree {
|
||||
public:
|
||||
// Add a prefix to the tree.
|
||||
// Optionally pass node_count to get the number of nodes after the add.
|
||||
@@ -43,8 +43,8 @@ class SantaPrefixTree {
|
||||
// Reset the tree.
|
||||
void Reset();
|
||||
|
||||
SantaPrefixTree(uint32_t max_nodes = kDefaultMaxNodes);
|
||||
~SantaPrefixTree();
|
||||
SNTPrefixTree(uint32_t max_nodes = kDefaultMaxNodes);
|
||||
~SNTPrefixTree();
|
||||
|
||||
private:
|
||||
///
|
||||
@@ -85,19 +85,19 @@ class SantaPrefixTree {
|
||||
uint32_t max_nodes_;
|
||||
uint32_t node_count_;
|
||||
|
||||
#ifdef KERNEL
|
||||
#ifdef KERNEL
|
||||
lck_grp_t *spt_lock_grp_;
|
||||
lck_grp_attr_t *spt_lock_grp_attr_;
|
||||
lck_attr_t *spt_lock_attr_;
|
||||
lck_rw_t *spt_lock_;
|
||||
lck_mtx_t *spt_add_lock_;
|
||||
#else // KERNEL
|
||||
#else // KERNEL
|
||||
void *spt_lock_grp_;
|
||||
void *spt_lock_grp_attr_;
|
||||
void *spt_lock_attr_;
|
||||
std::shared_mutex *spt_lock_;
|
||||
pthread_rwlock_t spt_lock_;
|
||||
std::mutex *spt_add_lock_;
|
||||
#endif // KERNEL
|
||||
#endif // KERNEL
|
||||
};
|
||||
|
||||
#endif /* SANTA__SANTA_DRIVER__SANTAPREFIXTREE_H */
|
||||
@@ -14,22 +14,22 @@
|
||||
|
||||
#import <XCTest/XCTest.h>
|
||||
|
||||
#include "Source/santa_driver/SantaPrefixTree.h"
|
||||
#include "Source/common/SNTPrefixTree.h"
|
||||
|
||||
@interface SantaPrefixTreeTest : XCTestCase
|
||||
@interface SNTPrefixTreeTest : XCTestCase
|
||||
@end
|
||||
|
||||
@implementation SantaPrefixTreeTest
|
||||
@implementation SNTPrefixTreeTest
|
||||
|
||||
- (void)testAddAndHas {
|
||||
auto t = SantaPrefixTree();
|
||||
auto t = SNTPrefixTree();
|
||||
XCTAssertFalse(t.HasPrefix("/private/var/tmp/file1"));
|
||||
t.AddPrefix("/private/var/tmp/");
|
||||
XCTAssertTrue(t.HasPrefix("/private/var/tmp/file1"));
|
||||
}
|
||||
|
||||
- (void)testReset {
|
||||
auto t = SantaPrefixTree();
|
||||
auto t = SNTPrefixTree();
|
||||
t.AddPrefix("/private/var/tmp/");
|
||||
XCTAssertTrue(t.HasPrefix("/private/var/tmp/file1"));
|
||||
t.Reset();
|
||||
@@ -38,7 +38,7 @@
|
||||
|
||||
- (void)testThreading {
|
||||
uint32_t count = 4096;
|
||||
auto t = new SantaPrefixTree(count * (uint32_t)[NSUUID UUID].UUIDString.length);
|
||||
auto t = new SNTPrefixTree(count * (uint32_t)[NSUUID UUID].UUIDString.length);
|
||||
|
||||
NSMutableArray *UUIDs = [NSMutableArray arrayWithCapacity:count];
|
||||
for (int i = 0; i < count; ++i) {
|
||||
@@ -18,8 +18,6 @@ cc_library(
|
||||
"SantaDriver.h",
|
||||
"SantaDriverClient.cc",
|
||||
"SantaDriverClient.h",
|
||||
"SantaPrefixTree.cc",
|
||||
"SantaPrefixTree.h",
|
||||
"main.cc",
|
||||
],
|
||||
copts = [
|
||||
@@ -39,6 +37,7 @@ cc_library(
|
||||
deps = [
|
||||
"//Source/common:SNTKernelCommon",
|
||||
"//Source/common:SNTLoggingKernel",
|
||||
"//Source/common:SNTPrefixTree",
|
||||
],
|
||||
alwayslink = 1,
|
||||
)
|
||||
@@ -52,25 +51,6 @@ santa_unit_test(
|
||||
deps = ["//Source/common:SNTKernelCommon"],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "SantaPrefixTree_userland_lib",
|
||||
srcs = ["SantaPrefixTree.cc"],
|
||||
hdrs = ["SantaPrefixTree.h"],
|
||||
copts = ["-std=c++1z"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
santa_unit_test(
|
||||
name = "SantaPrefixTreeTest",
|
||||
srcs = ["SantaPrefixTreeTest.mm"],
|
||||
copts = ["-std=c++1z"],
|
||||
minimum_os_version = "10.12",
|
||||
deps = [
|
||||
":SantaPrefixTree_userland_lib",
|
||||
"//Source/common:SNTKernelCommon"
|
||||
],
|
||||
)
|
||||
|
||||
# Full santa-driver.kext containing all Santa components
|
||||
macos_kernel_extension(
|
||||
name = "santa_driver",
|
||||
|
||||
@@ -58,7 +58,7 @@ bool SantaDecisionManager::init() {
|
||||
root_fsid_ = 0;
|
||||
|
||||
// Setup file modification prefix filter.
|
||||
filemod_prefix_filter_ = new SantaPrefixTree();
|
||||
filemod_prefix_filter_ = new SNTPrefixTree();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -25,8 +25,8 @@
|
||||
|
||||
#include "Source/common/SNTKernelCommon.h"
|
||||
#include "Source/common/SNTLogging.h"
|
||||
#include "Source/common/SNTPrefixTree.h"
|
||||
#include "Source/santa_driver/SantaCache.h"
|
||||
#include "Source/santa_driver/SantaPrefixTree.h"
|
||||
|
||||
///
|
||||
/// SantaDecisionManager is responsible for intercepting Vnode execute actions
|
||||
@@ -347,7 +347,7 @@ class SantaDecisionManager : public OSObject {
|
||||
SantaCache<santa_vnode_id_t, uint64_t> *vnode_pid_map_;
|
||||
SantaCache<pid_t, pid_t> *compiler_pid_set_;
|
||||
|
||||
SantaPrefixTree *filemod_prefix_filter_;
|
||||
SNTPrefixTree *filemod_prefix_filter_;
|
||||
|
||||
/**
|
||||
Return the correct cache for a given identifier.
|
||||
|
||||
@@ -15,7 +15,7 @@ objc_library(
|
||||
"EventProviders/SNTDriverManager.h",
|
||||
"EventProviders/SNTDriverManager.m",
|
||||
"EventProviders/SNTEndpointSecurityManager.h",
|
||||
"EventProviders/SNTEndpointSecurityManager.m",
|
||||
"EventProviders/SNTEndpointSecurityManager.mm",
|
||||
"EventProviders/SNTEventProvider.h",
|
||||
"Logs/SNTEventLog.h",
|
||||
"Logs/SNTEventLog.m",
|
||||
@@ -58,6 +58,7 @@ objc_library(
|
||||
"//Source/common:SNTFileInfo",
|
||||
"//Source/common:SNTKernelCommon",
|
||||
"//Source/common:SNTLogging",
|
||||
"//Source/common:SNTPrefixTree",
|
||||
"//Source/common:SNTRule",
|
||||
"//Source/common:SNTStoredEvent",
|
||||
"//Source/common:SNTXPCControlInterface",
|
||||
@@ -91,7 +92,7 @@ santa_unit_test(
|
||||
"EventProviders/SNTDriverManager.h",
|
||||
"EventProviders/SNTDriverManager.m",
|
||||
"EventProviders/SNTEndpointSecurityManager.h",
|
||||
"EventProviders/SNTEndpointSecurityManager.m",
|
||||
"EventProviders/SNTEndpointSecurityManager.mm",
|
||||
"EventProviders/SNTEventProvider.h",
|
||||
"Logs/SNTEventLog.h",
|
||||
"Logs/SNTEventLog.m",
|
||||
@@ -119,6 +120,7 @@ santa_unit_test(
|
||||
"//Source/common:SNTFileInfo",
|
||||
"//Source/common:SNTKernelCommon",
|
||||
"//Source/common:SNTLogging",
|
||||
"//Source/common:SNTPrefixTree",
|
||||
"//Source/common:SNTRule",
|
||||
"//Source/common:SNTXPCNotifierInterface",
|
||||
"//Source/common:SNTXPCSyncdInterface",
|
||||
|
||||
@@ -1,193 +0,0 @@
|
||||
/// Copyright 2019 Google Inc. All rights reserved.
|
||||
///
|
||||
/// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
/// you may not use this file except in compliance with the License.
|
||||
/// You may obtain a copy of the License at
|
||||
///
|
||||
/// http://www.apache.org/licenses/LICENSE-2.0
|
||||
///
|
||||
/// Unless required by applicable law or agreed to in writing, software
|
||||
/// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
/// See the License for the specific language governing permissions and
|
||||
/// limitations under the License.
|
||||
|
||||
#import "Source/santad/EventProviders/SNTEndpointSecurityManager.h"
|
||||
|
||||
#import "Source/common/SNTLogging.h"
|
||||
|
||||
#include <EndpointSecurity/EndpointSecurity.h>
|
||||
#include <bsm/libbsm.h>
|
||||
|
||||
@interface SNTEndpointSecurityManager ()
|
||||
|
||||
@property(nonatomic) es_client_t *client;
|
||||
@property (nonatomic, copy) void (^decisionCallback)(santa_message_t);
|
||||
@property (nonatomic, copy) void (^logCallback)(santa_message_t);
|
||||
|
||||
@end
|
||||
|
||||
@implementation SNTEndpointSecurityManager
|
||||
|
||||
- (instancetype)init API_AVAILABLE(macos(10.15)) {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
[self establishClient];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)establishClient API_AVAILABLE(macos(10.15)) {
|
||||
while (!self.client) {
|
||||
es_client_t *client = NULL;
|
||||
es_new_client_result_t ret = es_new_client(&client, ^(es_client_t *c, const es_message_t *m) {
|
||||
[self messageHandler:m];
|
||||
});
|
||||
|
||||
switch (ret) {
|
||||
case ES_NEW_CLIENT_RESULT_SUCCESS:
|
||||
LOGI(@"Connected to EndpointSecurity");
|
||||
self.client = client;
|
||||
return;
|
||||
case ES_NEW_CLIENT_RESULT_ERR_NOT_PERMITTED:
|
||||
LOGE(@"Unable to create EndpointSecurity client, not full-disk access permitted");
|
||||
LOGE(@"Sleeping for 30s before restarting.");
|
||||
sleep(30);
|
||||
exit(ret);
|
||||
default:
|
||||
LOGE(@"Unable to create es client: %d. Sleeping for a minute.", ret);
|
||||
sleep(60);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)messageHandler:(const es_message_t *)m API_AVAILABLE(macos(10.15)) {
|
||||
// TODO(bur/rah): Currently this class only subscribes to exec events. Move this code
|
||||
// somewhere exec specific if other types of events are added to this client.
|
||||
santa_message_t sm;
|
||||
sm.uid = audit_token_to_ruid(m->event.exec.target->audit_token);
|
||||
sm.gid = audit_token_to_rgid(m->event.exec.target->audit_token);
|
||||
sm.pid = audit_token_to_pid(m->event.exec.target->audit_token);
|
||||
// original_ppid stays constant even in the event a process is reparented
|
||||
sm.ppid = m->event.exec.target->original_ppid;
|
||||
sm.es_message = (void *)es_copy_message(m);
|
||||
|
||||
sm.vnode_id.fsid = m->event.exec.target->executable->stat.st_dev;
|
||||
sm.vnode_id.fileid = m->event.exec.target->executable->stat.st_ino;
|
||||
|
||||
size_t l = m->event.exec.target->executable->path.length;
|
||||
if (l + 1 > MAXPATHLEN || m->event.exec.target->executable->path_truncated) {
|
||||
// TODO(bur/rah): Get path from fsid.
|
||||
LOGE(@"Path is truncated!");
|
||||
es_respond_auth_result(self.client, m, ES_AUTH_RESULT_ALLOW, true);
|
||||
return;
|
||||
}
|
||||
strncpy(sm.path,m->event.exec.target->executable->path.data, l);
|
||||
sm.path[l] = '\0';
|
||||
|
||||
switch (m->event_type) {
|
||||
case ES_EVENT_TYPE_AUTH_EXEC:
|
||||
// // TODO(bur/rah): Probably also want to do this for is_es_client.
|
||||
// // TODO(bur/rah): Since these events are not evaluated by Santa's pipline they are
|
||||
// // missing bits of information such as SHA256 and REASON. Refactor the
|
||||
// // logging cache.
|
||||
// if (m->event.exec.target->is_platform_binary) {
|
||||
// LOGD(@"platform binary: %s", sm.path);
|
||||
// [self postAction:ACTION_RESPOND_ALLOW forMessage:sm];
|
||||
// return;
|
||||
// }
|
||||
sm.action = ACTION_REQUEST_BINARY;
|
||||
if (self.decisionCallback) self.decisionCallback(sm);
|
||||
break;
|
||||
case ES_EVENT_TYPE_NOTIFY_EXEC:
|
||||
sm.action = ACTION_NOTIFY_EXEC;
|
||||
if (self.logCallback) self.logCallback(sm);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)listenForDecisionRequests:(void (^)(santa_message_t))callback API_AVAILABLE(macos(10.15)) {
|
||||
while (!self.connectionEstablished) usleep(100000); // 100ms
|
||||
|
||||
// Listen for exec auth messages.
|
||||
self.decisionCallback = callback;
|
||||
es_event_type_t events[] = { ES_EVENT_TYPE_AUTH_EXEC };
|
||||
es_return_t sret = es_subscribe(self.client, events, 1);
|
||||
if (sret != ES_RETURN_SUCCESS) LOGE(@"Unable to subscribe ES_EVENT_TYPE_AUTH_EXEC: %d", sret);
|
||||
|
||||
// There's a gap between creating a client and subscribing to events. Creating the client
|
||||
// triggers a cache flush automatically but any events that happen in this gap could be allowed
|
||||
// and cached, so we force the cache to flush again.
|
||||
[self flushCacheNonRootOnly:YES];
|
||||
}
|
||||
|
||||
- (void)listenForLogRequests:(void (^)(santa_message_t))callback API_AVAILABLE(macos(10.15)) {
|
||||
while (!self.connectionEstablished) usleep(100000); // 100ms
|
||||
|
||||
// Listen for exec notify messages.
|
||||
self.logCallback = callback;
|
||||
es_event_type_t events[] = { ES_EVENT_TYPE_NOTIFY_EXEC };
|
||||
es_return_t sret = es_subscribe(self.client, events, 1);
|
||||
if (sret != ES_RETURN_SUCCESS) LOGE(@"Unable to subscribe ES_EVENT_TYPE_NOTIFY_EXEC: %d", sret);
|
||||
}
|
||||
|
||||
- (int)postAction:(santa_action_t)action forMessage:(santa_message_t)sm
|
||||
API_AVAILABLE(macos(10.15)) {
|
||||
es_respond_result_t ret;
|
||||
switch (action) {
|
||||
case ACTION_RESPOND_ALLOW:
|
||||
ret = es_respond_auth_result(self.client, (es_message_t *)sm.es_message,
|
||||
ES_AUTH_RESULT_ALLOW, true);
|
||||
break;
|
||||
case ACTION_RESPOND_DENY:
|
||||
ret = es_respond_auth_result(self.client, (es_message_t *)sm.es_message,
|
||||
ES_AUTH_RESULT_DENY, false);
|
||||
break;
|
||||
default:
|
||||
return ES_RESPOND_RESULT_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
if (sm.es_message) {
|
||||
es_free_message(sm.es_message);
|
||||
sm.es_message = NULL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
- (BOOL)flushCacheNonRootOnly:(BOOL)nonRootOnly API_AVAILABLE(macos(10.15)) {
|
||||
if (!self.connectionEstablished) return YES; // if not connected, there's nothing to flush.
|
||||
return es_clear_cache(self.client) == ES_CLEAR_CACHE_RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
- (void)fileModificationPrefixFilterAdd:(NSArray *)filters {
|
||||
}
|
||||
|
||||
- (void)fileModificationPrefixFilterReset {
|
||||
}
|
||||
|
||||
- (NSArray<NSNumber *> *)cacheCounts {
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (NSArray<NSNumber *> *)cacheBucketCount {
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (santa_action_t)checkCache:(santa_vnode_id_t)vnodeID {
|
||||
return ACTION_UNSET;
|
||||
}
|
||||
|
||||
- (kern_return_t)removeCacheEntryForVnodeID:(santa_vnode_id_t)vnodeId {
|
||||
return KERN_FAILURE;
|
||||
}
|
||||
|
||||
- (BOOL)connectionEstablished {
|
||||
return self.client != nil;
|
||||
}
|
||||
|
||||
@end
|
||||
306
Source/santad/EventProviders/SNTEndpointSecurityManager.mm
Normal file
306
Source/santad/EventProviders/SNTEndpointSecurityManager.mm
Normal file
@@ -0,0 +1,306 @@
|
||||
/// Copyright 2019 Google Inc. All rights reserved.
|
||||
///
|
||||
/// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
/// you may not use this file except in compliance with the License.
|
||||
/// You may obtain a copy of the License at
|
||||
///
|
||||
/// http://www.apache.org/licenses/LICENSE-2.0
|
||||
///
|
||||
/// Unless required by applicable law or agreed to in writing, software
|
||||
/// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
/// See the License for the specific language governing permissions and
|
||||
/// limitations under the License.
|
||||
|
||||
#import "Source/santad/EventProviders/SNTEndpointSecurityManager.h"
|
||||
#include "Source/common/SNTPrefixTree.h"
|
||||
|
||||
#import "Source/common/SNTLogging.h"
|
||||
|
||||
#include <EndpointSecurity/EndpointSecurity.h>
|
||||
#include <bsm/libbsm.h>
|
||||
#import <libproc.h>
|
||||
|
||||
@interface SNTEndpointSecurityManager ()
|
||||
|
||||
@property(nonatomic) es_client_t *client;
|
||||
@property(nonatomic) SNTPrefixTree *prefixTree;
|
||||
@property (nonatomic, copy) void (^decisionCallback)(santa_message_t);
|
||||
@property (nonatomic, copy) void (^logCallback)(santa_message_t);
|
||||
|
||||
@end
|
||||
|
||||
@implementation SNTEndpointSecurityManager
|
||||
|
||||
- (instancetype)init API_AVAILABLE(macos(10.15)) {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
[self establishClient];
|
||||
_prefixTree = new SNTPrefixTree();
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc API_AVAILABLE(macos(10.15)) {
|
||||
if (_prefixTree) delete _prefixTree;
|
||||
if (_client) {
|
||||
es_unsubscribe_all(_client);
|
||||
es_delete_client(_client);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)establishClient API_AVAILABLE(macos(10.15)) {
|
||||
while (!self.client) {
|
||||
es_client_t *client = NULL;
|
||||
es_new_client_result_t ret = es_new_client(&client, ^(es_client_t *c, const es_message_t *m) {
|
||||
[self messageHandler:m];
|
||||
});
|
||||
|
||||
switch (ret) {
|
||||
case ES_NEW_CLIENT_RESULT_SUCCESS:
|
||||
LOGI(@"Connected to EndpointSecurity");
|
||||
self.client = client;
|
||||
return;
|
||||
case ES_NEW_CLIENT_RESULT_ERR_NOT_PERMITTED:
|
||||
LOGE(@"Unable to create EndpointSecurity client, not full-disk access permitted");
|
||||
LOGE(@"Sleeping for 30s before restarting.");
|
||||
sleep(30);
|
||||
exit(ret);
|
||||
default:
|
||||
LOGE(@"Unable to create es client: %d. Sleeping for a minute.", ret);
|
||||
sleep(60);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)messageHandler:(const es_message_t *)m API_AVAILABLE(macos(10.15)) {
|
||||
santa_message_t sm = {};
|
||||
|
||||
audit_token_t audit_token = {};
|
||||
void (^callback)(santa_message_t);
|
||||
|
||||
switch (m->event_type) {
|
||||
case ES_EVENT_TYPE_AUTH_EXEC: {
|
||||
// // TODO(bur/rah): Probably also want to do this for is_es_client.
|
||||
// // TODO(bur/rah): Since these events are not evaluated by Santa's pipline they are
|
||||
// // missing bits of information such as SHA256 and REASON. Refactor the
|
||||
// // logging cache.
|
||||
// if (m->event.exec.target->is_platform_binary) {
|
||||
// LOGD(@"platform binary: %s", sm.path);
|
||||
// [self postAction:ACTION_RESPOND_ALLOW forMessage:sm];
|
||||
// return;
|
||||
// }
|
||||
sm.es_message = (void *)es_copy_message(m);
|
||||
sm.action = ACTION_REQUEST_BINARY;
|
||||
sm.vnode_id.fsid = m->event.exec.target->executable->stat.st_dev;
|
||||
sm.vnode_id.fileid = m->event.exec.target->executable->stat.st_ino;
|
||||
callback = self.decisionCallback;
|
||||
audit_token = m->event.exec.target->audit_token;
|
||||
sm.ppid = m->event.exec.target->original_ppid;
|
||||
|
||||
size_t l = m->event.exec.target->executable->path.length;
|
||||
if (l + 1 > MAXPATHLEN || m->event.exec.target->executable->path_truncated) {
|
||||
// TODO(bur/rah): Get path from fsid.
|
||||
LOGE(@"Path is truncated!");
|
||||
es_respond_auth_result(self.client, m, ES_AUTH_RESULT_ALLOW, true);
|
||||
return;
|
||||
}
|
||||
strncpy(sm.path,m->event.exec.target->executable->path.data, l);
|
||||
sm.path[l] = '\0';
|
||||
|
||||
break;
|
||||
}
|
||||
case ES_EVENT_TYPE_NOTIFY_EXEC: {
|
||||
sm.action = ACTION_NOTIFY_EXEC;
|
||||
sm.vnode_id.fsid = m->event.exec.target->executable->stat.st_dev;
|
||||
sm.vnode_id.fileid = m->event.exec.target->executable->stat.st_ino;
|
||||
|
||||
// TODO(rah): Profile this, it might need to be improved.
|
||||
uint32_t argCount = es_exec_arg_count(&(m->event.exec));
|
||||
NSMutableArray *args = [NSMutableArray arrayWithCapacity:argCount];
|
||||
for (int i = 0; i < argCount; ++i) {
|
||||
es_string_token_t arg = es_exec_arg(&(m->event.exec), i);
|
||||
[args addObject:[[NSString alloc] initWithBytes:arg.data
|
||||
length:arg.length
|
||||
encoding:NSUTF8StringEncoding]];
|
||||
}
|
||||
sm.args_array = (void *)CFBridgingRetain(args);
|
||||
|
||||
callback = self.logCallback;
|
||||
audit_token = m->event.exec.target->audit_token;
|
||||
sm.ppid = m->event.exec.target->original_ppid;
|
||||
|
||||
size_t l = m->event.exec.target->executable->path.length;
|
||||
strncpy(sm.path,m->event.exec.target->executable->path.data, l);
|
||||
sm.path[l] = '\0';
|
||||
|
||||
break;
|
||||
}
|
||||
case ES_EVENT_TYPE_NOTIFY_CLOSE: {
|
||||
if (!m->event.close.modified) return;
|
||||
sm.action = ACTION_NOTIFY_WRITE;
|
||||
sm.ppid = m->process->original_ppid;
|
||||
strncpy(sm.path, m->event.close.target->path.data, m->event.close.target->path.length);
|
||||
sm.path[m->event.close.target->path.length] = '\0';
|
||||
callback = self.logCallback;
|
||||
audit_token = m->process->audit_token;
|
||||
break;
|
||||
}
|
||||
case ES_EVENT_TYPE_NOTIFY_UNLINK:
|
||||
sm.action = ACTION_NOTIFY_DELETE;
|
||||
sm.ppid = m->process->original_ppid;
|
||||
strncpy(sm.path, m->event.unlink.target->path.data, m->event.unlink.target->path.length);
|
||||
sm.path[m->event.unlink.target->path.length] = '\0';
|
||||
callback = self.logCallback;
|
||||
audit_token = m->process->audit_token;
|
||||
case ES_EVENT_TYPE_NOTIFY_TRUNCATE: {
|
||||
sm.action = ACTION_NOTIFY_DELETE;
|
||||
sm.ppid = m->process->original_ppid;
|
||||
strncpy(sm.path, m->event.truncate.target->path.data, m->event.truncate.target->path.length);
|
||||
sm.path[m->event.truncate.target->path.length] = '\0';
|
||||
callback = self.logCallback;
|
||||
audit_token = m->process->audit_token;
|
||||
break;
|
||||
}
|
||||
case ES_EVENT_TYPE_NOTIFY_LINK: {
|
||||
sm.action = ACTION_NOTIFY_LINK;
|
||||
sm.ppid = m->process->original_ppid;
|
||||
strncpy(sm.path, m->event.link.source->path.data, m->event.link.source->path.length);
|
||||
sm.path[m->event.link.source->path.length] = '\0';
|
||||
strncpy(sm.newpath, m->event.link.target_filename.data, m->event.link.target_filename.length);
|
||||
sm.newpath[m->event.link.target_filename.length] = '\0';
|
||||
callback = self.logCallback;
|
||||
audit_token = m->process->audit_token;
|
||||
break;
|
||||
}
|
||||
case ES_EVENT_TYPE_NOTIFY_RENAME: {
|
||||
sm.action = ACTION_NOTIFY_RENAME;
|
||||
sm.ppid = m->process->original_ppid;
|
||||
strncpy(sm.path, m->event.rename.source->path.data, m->event.rename.source->path.length);
|
||||
sm.path[m->event.rename.source->path.length] = '\0';
|
||||
|
||||
switch(m->event.rename.destination_type) {
|
||||
case ES_DESTINATION_TYPE_NEW_PATH:
|
||||
strncpy(sm.newpath, m->event.rename.destination.new_path.filename.data, m->event.rename.destination.new_path.filename.length);
|
||||
sm.newpath[m->event.rename.destination.new_path.filename.length] = '\0';
|
||||
break;
|
||||
case ES_DESTINATION_TYPE_EXISTING_FILE:
|
||||
strncpy(sm.newpath, m->event.rename.destination.existing_file->path.data, m->event.rename.destination.existing_file->path.length);
|
||||
sm.newpath[m->event.rename.destination.existing_file->path.length] = '\0';
|
||||
break;
|
||||
}
|
||||
|
||||
callback = self.logCallback;
|
||||
audit_token = m->process->audit_token;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (self.prefixTree->HasPrefix(sm.path)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (callback) {
|
||||
sm.uid = audit_token_to_ruid(audit_token);
|
||||
sm.gid = audit_token_to_rgid(audit_token);
|
||||
sm.pid = audit_token_to_pid(audit_token);
|
||||
proc_name(sm.pid, sm.pname, 1024);
|
||||
callback(sm);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)listenForDecisionRequests:(void (^)(santa_message_t))callback API_AVAILABLE(macos(10.15)) {
|
||||
while (!self.connectionEstablished) usleep(100000); // 100ms
|
||||
|
||||
// Listen for exec auth messages.
|
||||
self.decisionCallback = callback;
|
||||
es_event_type_t events[] = { ES_EVENT_TYPE_AUTH_EXEC };
|
||||
es_return_t sret = es_subscribe(self.client, events, 1);
|
||||
if (sret != ES_RETURN_SUCCESS) LOGE(@"Unable to subscribe ES_EVENT_TYPE_AUTH_EXEC: %d", sret);
|
||||
|
||||
// There's a gap between creating a client and subscribing to events. Creating the client
|
||||
// triggers a cache flush automatically but any events that happen in this gap could be allowed
|
||||
// and cached, so we force the cache to flush again.
|
||||
[self flushCacheNonRootOnly:YES];
|
||||
}
|
||||
|
||||
- (void)listenForLogRequests:(void (^)(santa_message_t))callback API_AVAILABLE(macos(10.15)) {
|
||||
while (!self.connectionEstablished) usleep(100000); // 100ms
|
||||
|
||||
// Listen for exec notify messages.
|
||||
self.logCallback = callback;
|
||||
es_event_type_t events[] = {
|
||||
ES_EVENT_TYPE_NOTIFY_EXEC,
|
||||
ES_EVENT_TYPE_NOTIFY_CLOSE,
|
||||
ES_EVENT_TYPE_NOTIFY_TRUNCATE,
|
||||
ES_EVENT_TYPE_NOTIFY_LINK,
|
||||
ES_EVENT_TYPE_NOTIFY_RENAME,
|
||||
ES_EVENT_TYPE_NOTIFY_UNLINK,
|
||||
};
|
||||
es_return_t sret = es_subscribe(self.client, events, sizeof(events) / sizeof(es_event_type_t));
|
||||
if (sret != ES_RETURN_SUCCESS) LOGE(@"Unable to subscribe ES_EVENT_TYPE_NOTIFY_EXEC: %d", sret);
|
||||
}
|
||||
|
||||
- (int)postAction:(santa_action_t)action forMessage:(santa_message_t)sm
|
||||
API_AVAILABLE(macos(10.15)) {
|
||||
es_respond_result_t ret;
|
||||
switch (action) {
|
||||
case ACTION_RESPOND_ALLOW:
|
||||
ret = es_respond_auth_result(self.client, (es_message_t *)sm.es_message,
|
||||
ES_AUTH_RESULT_ALLOW, true);
|
||||
break;
|
||||
case ACTION_RESPOND_DENY:
|
||||
ret = es_respond_auth_result(self.client, (es_message_t *)sm.es_message,
|
||||
ES_AUTH_RESULT_DENY, false);
|
||||
break;
|
||||
default:
|
||||
ret = ES_RESPOND_RESULT_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
if (sm.es_message) {
|
||||
es_free_message((es_message_t *)sm.es_message);
|
||||
sm.es_message = NULL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
- (BOOL)flushCacheNonRootOnly:(BOOL)nonRootOnly API_AVAILABLE(macos(10.15)) {
|
||||
if (!self.connectionEstablished) return YES; // if not connected, there's nothing to flush.
|
||||
return es_clear_cache(self.client) == ES_CLEAR_CACHE_RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
- (void)fileModificationPrefixFilterAdd:(NSArray *)filters {
|
||||
for (NSString *filter in filters) {
|
||||
self.prefixTree->AddPrefix(filter.fileSystemRepresentation);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)fileModificationPrefixFilterReset {
|
||||
self.prefixTree->Reset();
|
||||
}
|
||||
|
||||
- (NSArray<NSNumber *> *)cacheCounts {
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (NSArray<NSNumber *> *)cacheBucketCount {
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (santa_action_t)checkCache:(santa_vnode_id_t)vnodeID {
|
||||
return ACTION_UNSET;
|
||||
}
|
||||
|
||||
- (kern_return_t)removeCacheEntryForVnodeID:(santa_vnode_id_t)vnodeId {
|
||||
return KERN_FAILURE;
|
||||
}
|
||||
|
||||
- (BOOL)connectionEstablished {
|
||||
return self.client != nil;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -182,18 +182,8 @@
|
||||
}
|
||||
|
||||
if (logArgs) {
|
||||
if (@available(macOS 10.15, *)) {
|
||||
es_message_t *m = (es_message_t *)message.es_message;
|
||||
|
||||
// TODO(rah): Profile this, it might need to be improved.
|
||||
uint32_t argCount = es_exec_arg_count(&(m->event.exec));
|
||||
NSMutableArray *args = [NSMutableArray arrayWithCapacity:argCount];
|
||||
for (int i = 0; i < argCount; ++i) {
|
||||
es_string_token_t arg = es_exec_arg(&(m->event.exec), i);
|
||||
[args addObject:[[NSString alloc] initWithBytes:arg.data
|
||||
length:arg.length
|
||||
encoding:NSUTF8StringEncoding]];
|
||||
}
|
||||
if (message.args_array) {
|
||||
NSArray *args = CFBridgingRelease(message.args_array);
|
||||
[outLog appendFormat:@"|args=%@", [args componentsJoinedByString:@" "]];
|
||||
} else {
|
||||
[self addArgsForPid:message.pid toString:outLog];
|
||||
|
||||
@@ -222,6 +222,7 @@
|
||||
case ACTION_NOTIFY_WRITE: {
|
||||
NSRegularExpression *re = [[SNTConfigurator configurator] fileChangesRegex];
|
||||
NSString *path = @(message.path);
|
||||
if (!path) break;
|
||||
if ([re numberOfMatchesInString:path options:0 range:NSMakeRange(0, path.length)]) {
|
||||
[self->_eventLog logFileModification:message];
|
||||
}
|
||||
|
||||
@@ -75,7 +75,7 @@
|
||||
|
||||
/// Return a pre-configured santa_message_ t for testing with.
|
||||
- (santa_message_t)getMessage {
|
||||
santa_message_t message = {0};
|
||||
santa_message_t message = {};
|
||||
message.pid = 12;
|
||||
message.ppid = 1;
|
||||
message.vnode_id = [self getVnodeId];
|
||||
|
||||
@@ -8,7 +8,7 @@ load("@bazel_tools//tools/build_defs/repo:git.bzl",
|
||||
git_repository(
|
||||
name = "build_bazel_rules_apple",
|
||||
remote = "https://github.com/bazelbuild/rules_apple.git",
|
||||
tag = "0.17.2",
|
||||
tag = "0.18.0",
|
||||
)
|
||||
|
||||
load("@build_bazel_rules_apple//apple:repositories.bzl", "apple_rules_dependencies")
|
||||
|
||||
Reference in New Issue
Block a user