Compare commits

...

3 Commits

Author SHA1 Message Date
Tom Burgin
5ee6531627 santad / santactl: validate all architectures within universal binaries (#249) 2018-04-24 16:11:49 -04:00
Tom Burgin
1cf8ee09e1 sync-state: Mitigate com.apple.ManagedClient flapping (#248)
* sync-state: Mitigate com.apple.ManagedClient flapping

* 10 min
2018-04-09 13:34:33 -04:00
Tom Burgin
4a2cf9d722 santad: event logger (#246)
* kext symbols

* santad: Create FileLog and Syslog options

* review updates

* review updates

* be a good citizen and let go of things you do not need
2018-04-03 13:15:12 -04:00
25 changed files with 653 additions and 276 deletions

1
.gitignore vendored
View File

@@ -9,3 +9,4 @@ Santa.xcodeproj/project.xcworkspace
Santa.xcworkspace/xcuserdata
Santa.xcworkspace/xcshareddata
Source/DevelopmentTeam.xcconfig
default.profraw

View File

@@ -32,6 +32,7 @@ PACKAGE_VERSION:=$(shell curl -fs https://api.github.com/repos/google/santa/rele
# | |-- com.google.santad.plist
# | |-- com.google.santagui.plist
# | +-- com.google.santa.asl.conf
# | +-- com.google.santa.newsyslog.conf
# +--dsym
# |-- santa-driver.kext.dSYM
# |-- Santa.app.dSYM
@@ -44,6 +45,7 @@ PAYLOAD:=pack-Library-Extensions-santa-driver.kext \
pack-Library-LaunchDaemons-com.google.santad.plist \
pack-Library-LaunchAgents-com.google.santagui.plist \
pack-etc-asl-com.google.santa.asl.conf \
pack-etc-newsyslog.d-com.google.santa.newsyslog.conf \
pack-script-preinstall \
pack-script-postinstall
@@ -52,6 +54,7 @@ Santa.app: download
com.google.santad.plist: download
com.google.santagui.plist: download
com.google.santa.asl.conf: download
com.google.santa.newsyslog.conf: download
download:
$(if $(PACKAGE_VERSION),, $(error GitHub API returned unexpected result. Wait a while and try again))
@@ -65,6 +68,12 @@ pack-etc-asl-com.google.santa.asl.conf: com.google.santa.asl.conf l_private_etc
@sudo chmod 755 ${WORK_D}/private/etc/asl
@sudo install -m 644 -o root -g wheel com.google.santa.asl.conf ${WORK_D}/private/etc/asl
pack-etc-newsyslog.d-com.google.santa.newsyslog.conf: com.google.santa.newsyslog.conf l_private_etc
@sudo mkdir -p ${WORK_D}/private/etc/newsyslog.d
@sudo chown root:wheel ${WORK_D}/private/etc/newsyslog.d
@sudo chmod 755 ${WORK_D}/private/etc/newsyslog.d
@sudo install -m 644 -o root -g wheel com.google.santa.newsyslog.conf ${WORK_D}/private/etc/newsyslog.d
pack-Library-Extensions-santa-driver.kext: santa-driver.kext l_Library
@sudo mkdir -p ${WORK_D}/Library/Extensions
@sudo ${DITTO} --noqtn santa-driver.kext ${WORK_D}/Library/Extensions/santa-driver.kext
@@ -79,6 +88,7 @@ myclean:
@rm -rf santa-driver.kext
@rm -f config.plist
@rm -f com.google.santa.asl.conf
@rm -f com.google.santa.newsyslog.conf
@rm -f com.google.santad.plist
@rm -f com.google.santagui.plist
@rm -f install.sh

View File

@@ -0,0 +1,2 @@
# logfilename [owner:group] mode count size(KiB) when flags [/pid_file] # [sig_num]
/var/db/santa/santa.log root:wheel 644 10 25000 * NZ

View File

@@ -42,6 +42,7 @@ mkdir -p /usr/local/bin
/bin/cp ${SOURCE}/conf/com.google.santad.plist /Library/LaunchDaemons
/bin/cp ${SOURCE}/conf/com.google.santagui.plist /Library/LaunchAgents
/bin/cp ${SOURCE}/conf/com.google.santa.asl.conf /etc/asl/
/bin/cp ${SOURCE}/conf/com.google.santa.newsyslog.conf /etc/newsyslog.d/
# Reload syslogd to pick up ASL configuration change.
/usr/bin/killall -HUP syslogd

View File

@@ -19,6 +19,7 @@ user=$(/usr/bin/stat -f '%u' /dev/console)
/bin/rm -f /Library/LaunchAgents/com.google.santagui.plist
/bin/rm -f /Library/LaunchDaemons/com.google.santad.plist
/bin/rm -f /private/etc/asl/com.google.santa.asl.conf
/bin/rm -f /private/etc/newsyslog.d/com.google.santa.newsyslog.conf
/bin/rm -f /usr/local/bin/santactl # just a symlink
#uncomment to remove the config file and all databases, log files
#/bin/rm -rf /var/db/santa

View File

@@ -5,7 +5,7 @@ PODS:
- MOLAuthenticatingURLSession (2.4):
- MOLCertificate (~> 1.8)
- MOLCertificate (1.8)
- MOLCodesignChecker (1.9):
- MOLCodesignChecker (1.10):
- MOLCertificate (~> 1.8)
- MOLFCMClient (1.7):
- MOLAuthenticatingURLSession (~> 2.4)
@@ -23,7 +23,7 @@ SPEC CHECKSUMS:
FMDB: 6198a90e7b6900cfc046e6bc0ef6ebb7be9236aa
MOLAuthenticatingURLSession: c238aa1c9a7b1077eb39a6f40204bfe76a7d204e
MOLCertificate: c999513316d511c69f290fbf313dfe8dca4ad592
MOLCodesignChecker: 303c01755646a0045c97f9f0b0fe5945ead42130
MOLCodesignChecker: b0d5db9d2f9bd94e0fd093891a5d40e5ad77cbc0
MOLFCMClient: ee45348909351f232e2759c580329072ae7e02d4
OCMock: 2cd0716969bab32a2283ff3a46fd26a8c8b4c5e3

View File

@@ -106,6 +106,7 @@ namespace :install do
system 'sudo cp conf/com.google.santad.plist /Library/LaunchDaemons'
system 'sudo cp conf/com.google.santagui.plist /Library/LaunchAgents'
system 'sudo cp conf/com.google.santa.asl.conf /etc/asl'
system 'sudo cp conf/com.google.santa.newsyslog.conf /etc/newsyslog.d/'
system '/usr/bin/killall -HUP syslogd'
Rake::Task['build:build'].invoke(config)
puts "Installing with configuration: #{config}"

View File

@@ -72,8 +72,6 @@
0D4644C6182AF81700098690 /* SantaDecisionManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 0D4644C4182AF81700098690 /* SantaDecisionManager.h */; };
0D536ED71B8E7A2E0039A26D /* bad_pagezero in Resources */ = {isa = PBXBuildFile; fileRef = 0D536ED51B8E7A2E0039A26D /* bad_pagezero */; };
0D536ED81B8E7A2E0039A26D /* missing_pagezero in Resources */ = {isa = PBXBuildFile; fileRef = 0D536ED61B8E7A2E0039A26D /* missing_pagezero */; };
0D536EDB1B94E9230039A26D /* SNTEventLog.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D536EDA1B94E9230039A26D /* SNTEventLog.m */; };
0D536EDC1B94E9230039A26D /* SNTEventLog.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D536EDA1B94E9230039A26D /* SNTEventLog.m */; };
0D63DD5C1906FCB400D346C4 /* SNTDatabaseController.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D63DD5B1906FCB400D346C4 /* SNTDatabaseController.m */; };
0D63DD5E1906FCB400D346C4 /* SNTDatabaseController.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D63DD5B1906FCB400D346C4 /* SNTDatabaseController.m */; };
0D668E8118D1121700E29A8B /* SNTMessageWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D668E8018D1121700E29A8B /* SNTMessageWindow.m */; };
@@ -164,6 +162,12 @@
C7479F051E53704E0054C1CF /* SNTXPCBundleServiceInterface.m in Sources */ = {isa = PBXBuildFile; fileRef = C7C721B01E23FF300051FAA6 /* SNTXPCBundleServiceInterface.m */; };
C7479F071E5374BF0054C1CF /* SNTXPCControlInterface.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DCD605419115D17006B445C /* SNTXPCControlInterface.m */; };
C7479F091E5374E50054C1CF /* SNTRule.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DE50F671912716A007B2B0C /* SNTRule.m */; };
C748E8A3206964E1006CFD1B /* SNTEventLog.m in Sources */ = {isa = PBXBuildFile; fileRef = C748E8A2206964DE006CFD1B /* SNTEventLog.m */; };
C748E8A4206964EE006CFD1B /* SNTEventLog.m in Sources */ = {isa = PBXBuildFile; fileRef = C748E8A2206964DE006CFD1B /* SNTEventLog.m */; };
C748E8A720696595006CFD1B /* SNTFileEventLog.m in Sources */ = {isa = PBXBuildFile; fileRef = C748E8A620696595006CFD1B /* SNTFileEventLog.m */; };
C748E8A820696595006CFD1B /* SNTFileEventLog.m in Sources */ = {isa = PBXBuildFile; fileRef = C748E8A620696595006CFD1B /* SNTFileEventLog.m */; };
C748E8B020697F01006CFD1B /* SNTSyslogEventLog.m in Sources */ = {isa = PBXBuildFile; fileRef = C748E8AF20697F01006CFD1B /* SNTSyslogEventLog.m */; };
C748E8B120697F01006CFD1B /* SNTSyslogEventLog.m in Sources */ = {isa = PBXBuildFile; fileRef = C748E8AF20697F01006CFD1B /* SNTSyslogEventLog.m */; };
C74D6CC61EEB3B9B00BB5A33 /* BundleExample.app in Resources */ = {isa = PBXBuildFile; fileRef = C74D6CC51EEB3B9B00BB5A33 /* BundleExample.app */; };
C76614EC1D142D3C00D150C1 /* SNTCommandCheckCache.m in Sources */ = {isa = PBXBuildFile; fileRef = C76614EB1D142D3C00D150C1 /* SNTCommandCheckCache.m */; };
C776A1071DEE160500A56616 /* SNTCommandSyncManager.m in Sources */ = {isa = PBXBuildFile; fileRef = C776A1061DEE160500A56616 /* SNTCommandSyncManager.m */; };
@@ -341,8 +345,6 @@
0D5058CF1CB70123008784BA /* SNTStrengthify.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SNTStrengthify.h; sourceTree = "<group>"; };
0D536ED51B8E7A2E0039A26D /* bad_pagezero */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.executable"; path = bad_pagezero; sourceTree = "<group>"; };
0D536ED61B8E7A2E0039A26D /* missing_pagezero */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.executable"; path = missing_pagezero; sourceTree = "<group>"; };
0D536ED91B94E9230039A26D /* SNTEventLog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SNTEventLog.h; sourceTree = "<group>"; };
0D536EDA1B94E9230039A26D /* SNTEventLog.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SNTEventLog.m; sourceTree = "<group>"; };
0D63DD5A1906FCB400D346C4 /* SNTDatabaseController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SNTDatabaseController.h; sourceTree = "<group>"; };
0D63DD5B1906FCB400D346C4 /* SNTDatabaseController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SNTDatabaseController.m; sourceTree = "<group>"; };
0D668E7F18D1121700E29A8B /* SNTMessageWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SNTMessageWindow.h; sourceTree = "<group>"; };
@@ -429,6 +431,12 @@
A6A91785C40257CC156B4F05 /* Pods-Santa.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Santa.release.xcconfig"; path = "Pods/Target Support Files/Pods-Santa/Pods-Santa.release.xcconfig"; sourceTree = "<group>"; };
C11A10A5D6E112788769CF70 /* libPods-santad.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-santad.a"; sourceTree = BUILT_PRODUCTS_DIR; };
C72E8D931D7F399900C86DD3 /* SNTCommandFileInfoTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SNTCommandFileInfoTest.m; sourceTree = "<group>"; };
C748E8A1206964DE006CFD1B /* SNTEventLog.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SNTEventLog.h; sourceTree = "<group>"; };
C748E8A2206964DE006CFD1B /* SNTEventLog.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SNTEventLog.m; sourceTree = "<group>"; };
C748E8A520696594006CFD1B /* SNTFileEventLog.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SNTFileEventLog.h; sourceTree = "<group>"; };
C748E8A620696595006CFD1B /* SNTFileEventLog.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SNTFileEventLog.m; sourceTree = "<group>"; };
C748E8AE20697F01006CFD1B /* SNTSyslogEventLog.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SNTSyslogEventLog.h; sourceTree = "<group>"; };
C748E8AF20697F01006CFD1B /* SNTSyslogEventLog.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SNTSyslogEventLog.m; sourceTree = "<group>"; };
C74D6CC51EEB3B9B00BB5A33 /* BundleExample.app */ = {isa = PBXFileReference; lastKnownFileType = wrapper.application; path = BundleExample.app; sourceTree = "<group>"; };
C76614EB1D142D3C00D150C1 /* SNTCommandCheckCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SNTCommandCheckCache.m; sourceTree = "<group>"; };
C776A1051DEE160500A56616 /* SNTCommandSyncManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SNTCommandSyncManager.h; sourceTree = "<group>"; };
@@ -752,6 +760,7 @@
isa = PBXGroup;
children = (
0DA73CA519363C9F0056D7C4 /* DataLayer */,
C748E8A020696001006CFD1B /* Logs */,
0D9A7F411759330500035EB5 /* main.m */,
0DB8ACBF185662DC00FEF9C7 /* SNTApplication.h */,
0DB8ACC0185662DC00FEF9C7 /* SNTApplication.m */,
@@ -765,8 +774,6 @@
C795ED8F1D80A5BE007CFF42 /* SNTPolicyProcessor.m */,
0D7D01851774F93A005DBAB4 /* SNTDriverManager.h */,
0D7D01861774F93A005DBAB4 /* SNTDriverManager.m */,
0D536ED91B94E9230039A26D /* SNTEventLog.h */,
0D536EDA1B94E9230039A26D /* SNTEventLog.m */,
0DE6788B1784A8C2007A9E52 /* SNTExecutionController.h */,
0DE6788C1784A8C2007A9E52 /* SNTExecutionController.m */,
0DE5B5491C926E3300C00603 /* SNTNotificationQueue.h */,
@@ -840,6 +847,19 @@
name = Frameworks;
sourceTree = "<group>";
};
C748E8A020696001006CFD1B /* Logs */ = {
isa = PBXGroup;
children = (
C748E8A1206964DE006CFD1B /* SNTEventLog.h */,
C748E8A2206964DE006CFD1B /* SNTEventLog.m */,
C748E8AE20697F01006CFD1B /* SNTSyslogEventLog.h */,
C748E8AF20697F01006CFD1B /* SNTSyslogEventLog.m */,
C748E8A520696594006CFD1B /* SNTFileEventLog.h */,
C748E8A620696595006CFD1B /* SNTFileEventLog.m */,
);
path = Logs;
sourceTree = "<group>";
};
C79A23541E23F7E80037AFA8 /* santabs */ = {
isa = PBXGroup;
children = (
@@ -1437,8 +1457,9 @@
C7DA62F71E241938009BDF2C /* SNTXPCBundleServiceInterface.m in Sources */,
C714F8B11D8044D400700EDF /* SNTCommandFileInfo.m in Sources */,
0D88680C1AC48A1400B86659 /* SNTSystemInfo.m in Sources */,
0D536EDC1B94E9230039A26D /* SNTEventLog.m in Sources */,
0DEA5F7D1CF64EB600704398 /* SNTCommandSyncRuleDownload.m in Sources */,
C748E8A4206964EE006CFD1B /* SNTEventLog.m in Sources */,
C748E8B120697F01006CFD1B /* SNTSyslogEventLog.m in Sources */,
C73A4B9B1DC10758007B6789 /* SNTXPCSyncdInterface.m in Sources */,
0DB77FDB1CD14093004DF060 /* SNTBlockMessage.m in Sources */,
0D63DD5E1906FCB400D346C4 /* SNTDatabaseController.m in Sources */,
@@ -1457,6 +1478,7 @@
0D10BE891A0AAF6700C0C944 /* SNTDropRootPrivs.m in Sources */,
C795ED911D80B66B007CFF42 /* SNTPolicyProcessor.m in Sources */,
C72E8D941D7F399900C86DD3 /* SNTCommandFileInfoTest.m in Sources */,
C748E8A820696595006CFD1B /* SNTFileEventLog.m in Sources */,
0D28D53819D9F5910015C5EB /* SNTConfigurator.m in Sources */,
0DE5B54C1C92722300C00603 /* SNTNotificationQueue.m in Sources */,
0DEA5F651CF6057D00704398 /* SNTCommandSyncEventUpload.m in Sources */,
@@ -1558,6 +1580,7 @@
0D8868091AC48A1100B86659 /* SNTSystemInfo.m in Sources */,
0DE6788D1784A8C2007A9E52 /* SNTExecutionController.m in Sources */,
0D10BE861A0AABD600C0C944 /* SNTDropRootPrivs.m in Sources */,
C748E8B020697F01006CFD1B /* SNTSyslogEventLog.m in Sources */,
0D63DD5C1906FCB400D346C4 /* SNTDatabaseController.m in Sources */,
0DCD604B19105433006B445C /* SNTStoredEvent.m in Sources */,
C7FB57001DBFC213004E14EF /* SNTSyncdQueue.m in Sources */,
@@ -1576,10 +1599,11 @@
0DE50F681912716A007B2B0C /* SNTRule.m in Sources */,
0DB77FD81CCE824A004DF060 /* SNTBlockMessage.m in Sources */,
0D37C10F18F6029A0069BC61 /* SNTDatabaseTable.m in Sources */,
C748E8A720696595006CFD1B /* SNTFileEventLog.m in Sources */,
C748E8A3206964E1006CFD1B /* SNTEventLog.m in Sources */,
0D42D2B819D2042900955F08 /* SNTConfigurator.m in Sources */,
0DCD605519115D17006B445C /* SNTXPCControlInterface.m in Sources */,
C795ED901D80A5BE007CFF42 /* SNTPolicyProcessor.m in Sources */,
0D536EDB1B94E9230039A26D /* SNTEventLog.m in Sources */,
0DCD604F19115A06006B445C /* SNTXPCNotifierInterface.m in Sources */,
0DE5B54B1C926E3300C00603 /* SNTNotificationQueue.m in Sources */,
);
@@ -2026,6 +2050,7 @@
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ENABLE_CODE_COVERAGE = NO;
CLANG_ENABLE_MODULES = NO;
CLANG_STATIC_ANALYZER_MODE = deep;
CLANG_WARN_CONSTANT_CONVERSION = YES;
@@ -2064,6 +2089,7 @@
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ENABLE_CODE_COVERAGE = NO;
CLANG_ENABLE_MODULES = NO;
CLANG_STATIC_ANALYZER_MODE = deep;
CLANG_WARN_CONSTANT_CONVERSION = YES;

View File

@@ -80,6 +80,12 @@ typedef NS_ENUM(NSInteger, SNTBundleEventAction) {
SNTBundleEventActionSendEvents,
};
// Indicates where to store event logs.
typedef NS_ENUM(NSInteger, SNTEventLogType) {
SNTEventLogTypeSyslog,
SNTEventLogTypeFilelog,
};
static const char *kKextPath = "/Library/Extensions/santa-driver.kext";
static const char *kSantaDPath = "/Library/Extensions/santa-driver.kext/Contents/MacOS/santad";
static const char *kSantaCtlPath = "/Library/Extensions/santa-driver.kext/Contents/MacOS/santactl";

View File

@@ -79,6 +79,25 @@
///
@property(readonly, nonatomic) BOOL enablePageZeroProtection;
///
/// Defines how event logs are stored. Options are:
/// SNTEventLogTypeSyslog: Sent to ASL or ULS (if built with the 10.12 SDK or later).
/// SNTEventLogTypeFilelog: Sent to a file on disk. Use eventLogPath to specify a path.
/// Defaults to SNTEventLogTypeFilelog.
/// For mobileconfigs use EventLogType as the key and syslog or filelog strings as the value.
///
/// @note: This property is KVO compliant, but should only be read once at santad startup.
///
@property(readonly, nonatomic) SNTEventLogType eventLogType;
///
/// If eventLogType is set to Filelog, eventLogPath will provide the path to save logs.
/// Defaults to /var/db/santa/santa.log.
///
/// @note: This property is KVO compliant, but should only be read once at santad startup.
///
@property(readonly, nonatomic) NSString *eventLogPath;
#pragma mark - GUI Settings
///

View File

@@ -69,6 +69,9 @@ static NSString *const kEnablePageZeroProtectionKey = @"EnablePageZeroProtection
static NSString *const kFileChangesRegexKey = @"FileChangesRegex";
static NSString *const kEventLogType = @"EventLogType";
static NSString *const kEventLogPath = @"EventLogPath";
// The keys managed by a sync server or mobileconfig.
static NSString *const kClientModeKey = @"ClientMode";
static NSString *const kWhitelistRegexKey = @"WhitelistRegex";
@@ -121,6 +124,8 @@ static NSString *const kSyncCleanRequired = @"SyncCleanRequired";
kMachineOwnerPlistKeyKey : string,
kMachineIDPlistFileKey : string,
kMachineIDPlistKeyKey : string,
kEventLogType : string,
kEventLogPath : string,
};
_defaults = [NSUserDefaults standardUserDefaults];
[_defaults addSuiteNamed:@"com.google.santa"];
@@ -267,6 +272,14 @@ static NSString *const kSyncCleanRequired = @"SyncCleanRequired";
return [self syncStateSet];
}
+ (NSSet *)keyPathsForValuesAffectingEventLogType {
return [self configStateSet];
}
+ (NSSet *)keyPathsForValuesAffectingEventLogPath {
return [self configStateSet];
}
#pragma mark Public Interface
- (SNTClientMode)clientMode {
@@ -429,6 +442,15 @@ static NSString *const kSyncCleanRequired = @"SyncCleanRequired";
return machineId.length ? machineId : [SNTSystemInfo hardwareUUID];
}
- (SNTEventLogType)eventLogType {
NSString *s = [self.configState[kEventLogType] lowercaseString];
return [s isEqualToString:@"syslog"] ? SNTEventLogTypeSyslog : SNTEventLogTypeFilelog;
}
- (NSString *)eventLogPath {
return self.configState[kEventLogPath] ?: @"/var/db/santa/santa.log";
}
#pragma mark Private
///

View File

@@ -212,6 +212,11 @@
///
- (NSUInteger)fileSize;
///
/// @return The underlying file handle.
///
@property(readonly) NSFileHandle *fileHandle;
///
/// @return Returns an instance of MOLCodeSignChecker initialized with the file's binary path.
/// Both the MOLCodesignChecker and any resulting NSError are cached and returned on subsequent

View File

@@ -17,6 +17,7 @@
#import <CommonCrypto/CommonDigest.h>
#import <MOLCodesignChecker/MOLCodesignChecker.h>
#include <mach-o/arch.h>
#include <mach-o/loader.h>
#include <mach-o/swap.h>
#include <pwd.h>
@@ -287,7 +288,8 @@ extern NSString *const NSURLQuarantinePropertiesKey WEAK_IMPORT_ATTRIBUTE;
- (BOOL)isMissingPageZero {
// This method only checks i386 arch because the kernel enforces this for other archs
// See bsd/kern/mach_loader.c, search for enforce_hard_pagezero.
MachHeaderWithOffset *x86Header = self.machHeaders[[self nameForCPUType:CPU_TYPE_X86]];
MachHeaderWithOffset *x86Header = self.machHeaders[[self nameForCPUType:CPU_TYPE_X86
cpuSubType:CPU_SUBTYPE_I386_ALL]];
if (!x86Header) return NO;
struct mach_header *mh = (struct mach_header *)[x86Header.data bytes];
@@ -443,7 +445,7 @@ extern NSString *const NSURLQuarantinePropertiesKey WEAK_IMPORT_ATTRIBUTE;
if (machHeader) {
struct mach_header *mh = (struct mach_header *)[machHeader bytes];
MachHeaderWithOffset *mhwo = [[MachHeaderWithOffset alloc] initWithData:machHeader offset:0];
machHeaders[[self nameForCPUType:mh->cputype]] = mhwo;
machHeaders[[self nameForCPUType:mh->cputype cpuSubType:mh->cpusubtype]] = mhwo;
} else {
NSRange range = NSMakeRange(0, sizeof(struct fat_header));
NSData *fatHeader = [self safeSubdataWithRange:range];
@@ -459,11 +461,12 @@ extern NSString *const NSURLQuarantinePropertiesKey WEAK_IMPORT_ATTRIBUTE;
int offset = OSSwapBigToHostInt32(fat_arch[i].offset);
int size = OSSwapBigToHostInt32(fat_arch[i].size);
int cputype = OSSwapBigToHostInt(fat_arch[i].cputype);
int cpusubtype = OSSwapBigToHostInt(fat_arch[i].cpusubtype);
range = NSMakeRange(offset, size);
NSData *machHeader = [self parseSingleMachHeader:[self safeSubdataWithRange:range]];
if (machHeader) {
NSString *key = [self nameForCPUType:cputype];
NSString *key = [self nameForCPUType:cputype cpuSubType:cpusubtype];
MachHeaderWithOffset *mhwo = [[MachHeaderWithOffset alloc] initWithData:machHeader
offset:offset];
machHeaders[key] = mhwo;
@@ -647,20 +650,15 @@ extern NSString *const NSURLQuarantinePropertiesKey WEAK_IMPORT_ATTRIBUTE;
///
/// Return a human-readable string for a cpu_type_t.
///
- (NSString *)nameForCPUType:(cpu_type_t)cpuType {
switch (cpuType) {
case CPU_TYPE_X86:
return @"i386";
case CPU_TYPE_X86_64:
return @"x86-64";
case CPU_TYPE_POWERPC:
return @"ppc";
case CPU_TYPE_POWERPC64:
return @"ppc64";
default:
return @"unknown";
- (NSString *)nameForCPUType:(cpu_type_t)cpuType cpuSubType:(cpu_subtype_t)cpuSubType {
const NXArchInfo *archInfo = NXGetArchInfoFromCpuType(cpuType, cpuSubType);
NSString *arch;
if (archInfo && archInfo->name) {
arch = @(archInfo->name);
} else {
arch = [NSString stringWithFormat:@"%i:%i", cpuType, cpuSubType];
}
return nil;
return arch;
}
///

View File

@@ -29,12 +29,12 @@ void syslogClientDestructor(void *arg) {
void logMessage(LogLevel level, FILE *destination, NSString *format, ...) {
static BOOL useSyslog = NO;
static const char *binaryName;
static NSString *binaryName;
static dispatch_once_t pred;
static pthread_key_t syslogKey = 0;
dispatch_once(&pred, ^{
binaryName = [[[NSProcessInfo processInfo] processName] UTF8String];
binaryName = [[NSProcessInfo processInfo] processName];
// If debug logging is enabled, the process must be restarted.
if ([[[NSProcessInfo processInfo] arguments] containsObject:@"--debug"]) {
@@ -76,7 +76,7 @@ void logMessage(LogLevel level, FILE *destination, NSString *format, ...) {
break;
case LOG_LEVEL_INFO:
levelName = "I";
syslogLevel = ASL_LEVEL_INFO;
syslogLevel = ASL_LEVEL_NOTICE; // Maps to ULS Default
break;
case LOG_LEVEL_DEBUG:
levelName = "D";
@@ -84,7 +84,7 @@ void logMessage(LogLevel level, FILE *destination, NSString *format, ...) {
break;
}
asl_log(client, NULL, syslogLevel, "%s %s: %s", levelName, binaryName, [s UTF8String]);
asl_log(client, NULL, syslogLevel, "%s %s: %s", levelName, binaryName.UTF8String, s.UTF8String);
} else {
[s appendString:@"\n"];
size_t len = [s lengthOfBytesUsingEncoding:NSUTF8StringEncoding];

View File

@@ -42,6 +42,7 @@ static NSString *const kPageZero = @"Page Zero";
static NSString *const kCodeSigned = @"Code-signed";
static NSString *const kRule = @"Rule";
static NSString *const kSigningChain = @"Signing Chain";
static NSString *const kUniversalSigningChain = @"Universal Signing Chain";
// signing chain keys
static NSString *const kCommonName = @"Common Name";
@@ -115,6 +116,7 @@ typedef id (^SNTAttributeBlock)(SNTCommandFileInfo *, SNTFileInfo *);
@property(readonly, copy, nonatomic) SNTAttributeBlock codeSigned;
@property(readonly, copy, nonatomic) SNTAttributeBlock rule;
@property(readonly, copy, nonatomic) SNTAttributeBlock signingChain;
@property(readonly, copy, nonatomic) SNTAttributeBlock universalSigningChain;
// Mapping between property string keys and SNTAttributeBlocks
@property(nonatomic) NSDictionary<NSString *, SNTAttributeBlock> *propertyMap;
@@ -182,7 +184,7 @@ REGISTER_COMMAND_NAME(@"fileinfo")
+ (NSArray<NSString *> *)fileInfoKeys {
return @[ kPath, kSHA256, kSHA1, kBundleName, kBundleVersion, kBundleVersionStr,
kDownloadReferrerURL, kDownloadURL, kDownloadTimestamp, kDownloadAgent,
kType, kPageZero, kCodeSigned, kRule, kSigningChain ];
kType, kPageZero, kCodeSigned, kRule, kSigningChain, kUniversalSigningChain ];
}
+ (NSArray<NSString *> *)signingChainKeys {
@@ -210,7 +212,8 @@ REGISTER_COMMAND_NAME(@"fileinfo")
kPageZero : self.pageZero,
kCodeSigned : self.codeSigned,
kRule : self.rule,
kSigningChain : self.signingChain };
kSigningChain : self.signingChain,
kUniversalSigningChain : self.universalSigningChain };
_printQueue = dispatch_queue_create("com.google.santactl.print_queue", DISPATCH_QUEUE_SERIAL);
}
@@ -325,6 +328,10 @@ REGISTER_COMMAND_NAME(@"fileinfo")
return @"Yes, but failed requirement validation";
case errSecCSInfoPlistFailed:
return @"Yes, but can't validate as Info.plist is missing";
case errSecCSSignatureInvalid:
if ([error.domain isEqualToString:@"com.google.molcodesignchecker"]) {
return @"Yes, but signing is not consistent for all architectures";
}
default: {
return [NSString stringWithFormat:@"Yes, but failed to validate (%ld)", error.code];
}
@@ -418,6 +425,46 @@ REGISTER_COMMAND_NAME(@"fileinfo")
};
}
- (SNTAttributeBlock)universalSigningChain {
return ^id (SNTCommandFileInfo *cmd, SNTFileInfo *fileInfo) {
MOLCodesignChecker *csc = [fileInfo codesignCheckerWithError:NULL];
if (csc.certificates.count) return nil;
if (!csc.universalSigningInformation) return nil;
NSMutableArray *universal = [NSMutableArray array];
for (NSDictionary *arch in csc.universalSigningInformation) {
[universal addObject:@{ @"arch" : arch.allKeys.firstObject }];
int flags = [arch.allValues.firstObject[(__bridge id)kSecCodeInfoFlags] intValue];
if (flags & kSecCodeSignatureAdhoc) {
[universal addObject:@{ @"ad-hoc" : @YES }];
continue;
}
NSArray *certs = arch.allValues.firstObject[(__bridge id)kSecCodeInfoCertificates];
NSArray *chain = [MOLCertificate certificatesFromArray:certs];
if (!chain.count) {
[universal addObject:@{ @"unsigned" : @YES }];
continue;
}
for (MOLCertificate *c in chain) {
[universal addObject:@{
kSHA256 : c.SHA256 ?: @"null",
kSHA1 : c.SHA1 ?: @"null",
kCommonName : c.commonName ?: @"null",
kOrganization : c.orgName ?: @"null",
kOrganizationalUnit : c.orgUnit ?: @"null",
kValidFrom : [cmd.dateFormatter stringFromDate:c.validFrom] ?: @"null",
kValidUntil : [cmd.dateFormatter stringFromDate:c.validUntil] ?: @"null"
}];
}
}
NSMutableSet *set = [NSMutableSet set];
for (NSDictionary *cert in universal) {
if (cert[@"arch"]) continue;
[set addObject:cert];
}
return (set.count > 1) ? universal : nil;
};
}
# pragma mark -
// Entry point for the command.
@@ -591,8 +638,8 @@ REGISTER_COMMAND_NAME(@"fileinfo")
} else {
for (NSString *key in self.outputKeyList) {
if (![outputDict objectForKey:key]) continue;
if ([key isEqual:kSigningChain]) {
[output appendString:[self stringForSigningChain:outputDict[key]]];
if ([key isEqual:kSigningChain] || [key isEqual:kUniversalSigningChain]) {
[output appendString:[self stringForSigningChain:outputDict[key] key:key]];
} else {
if (singleKey) {
[output appendFormat:@"%@\n", outputDict[key]];
@@ -729,14 +776,25 @@ REGISTER_COMMAND_NAME(@"fileinfo")
return [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
}
- (NSString *)stringForSigningChain:(NSArray *)signingChain {
- (NSString *)stringForSigningChain:(NSArray *)signingChain key:(NSString *)key {
if (!signingChain) return @"";
NSMutableString *result = [NSMutableString string];
[result appendFormat:@"%@:\n", kSigningChain];
[result appendFormat:@"%@:\n", key];
int i = 1;
NSArray<NSString *> *certKeys = [[self class] signingChainKeys];
for (NSDictionary *cert in signingChain) {
if ([cert isEqual:[NSNull null]]) continue;
if (cert[@"arch"]) {
[result appendFormat:@" %2@\n", [@"Architecture: " stringByAppendingString:cert[@"arch"]]];
i = 1;
continue;
} else if (cert[@"ad-hoc"]) {
[result appendFormat:@" %2d. %-20@\n", i, @"ad-hoc"];
continue;
} else if (cert[@"unsigned"]) {
[result appendFormat:@" %2d. %-20@\n", i, @"unsigned"];
continue;
}
if (i > 1) [result appendFormat:@"\n"];
[result appendString:[self stringForCertificate:cert withKeys:certKeys index:i]];
i += 1;
@@ -750,10 +808,10 @@ REGISTER_COMMAND_NAME(@"fileinfo")
BOOL firstKey = YES;
for (NSString *key in keys) {
if (firstKey) {
[result appendFormat:@" %2d. %-20s: %@\n", index, key.UTF8String, cert[key]];
[result appendFormat:@" %2d. %-20s: %@\n", index, key.UTF8String, cert[key]];
firstKey = NO;
} else {
[result appendFormat:@" %-20s: %@\n", key.UTF8String, cert[key]];
[result appendFormat:@" %-20s: %@\n", key.UTF8String, cert[key]];
}
}
return result.copy;

View File

@@ -1,4 +1,4 @@
/// Copyright 2015 Google Inc. All rights reserved.
/// Copyright 2018 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.
@@ -23,15 +23,32 @@
/// Logs execution and file write events to syslog
///
@interface SNTEventLog : NSObject
// Methods implemented by a concrete subclass.
- (void)logDiskAppeared:(NSDictionary *)diskProperties;
- (void)logDiskDisappeared:(NSDictionary *)diskProperties;
- (void)logFileModification:(santa_message_t)message;
- (void)saveDecisionDetails:(SNTCachedDecision *)cd;
- (void)logDeniedExecution:(SNTCachedDecision *)cd withMessage:(santa_message_t)message;
- (void)logAllowedExecution:(santa_message_t)message;
- (void)logBundleHashingEvents:(NSArray<SNTStoredEvent *> *)events;
// Getter and setter for cached decisions.
- (SNTCachedDecision *)cachedDecisionForMessage:(santa_message_t)message;
- (void)cacheDecision:(SNTCachedDecision *)cd;
// String formatter helpers.
- (void)addArgsForPid:(pid_t)pid toString:(NSMutableString *)str;
- (NSString *)diskImageForDevice:(NSString *)devPath;
- (NSString *)nameForUID:(uid_t)uid;
- (NSString *)nameForGID:(gid_t)gid;
- (NSString *)sanitizeCString:(const char *)str ofLength:(NSUInteger)length;
- (NSString *)sanitizeString:(NSString *)inStr;
- (NSString *)serialForDevice:(NSString *)devPath;
- (NSString *)originalPathForTranslocation:(santa_message_t)message;
// A cache for usernames and groups.
@property(readonly, nonatomic) NSCache<NSNumber *, NSString *> *userNameMap;
@property(readonly, nonatomic) NSCache<NSNumber *, NSString *> *groupNameMap;
// A UTC Date formatter.
@property(readonly, nonatomic) NSDateFormatter *dateFormatter;
@end

View File

@@ -1,4 +1,4 @@
/// Copyright 2015 Google Inc. All rights reserved.
/// Copyright 2018 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.
@@ -16,29 +16,14 @@
#include <dlfcn.h>
#include <grp.h>
#include <libproc.h>
#include <pwd.h>
#include <sys/sysctl.h>
#import <MOLCertificate/MOLCertificate.h>
#import "SNTCachedDecision.h"
#import "SNTCommonEnums.h"
#import "SNTConfigurator.h"
#import "SNTFileInfo.h"
#import "SNTKernelCommon.h"
#import "SNTLogging.h"
#import "SNTStoredEvent.h"
@interface SNTEventLog ()
@property NSMutableDictionary<NSNumber *, SNTCachedDecision *> *detailStore;
@property dispatch_queue_t detailStoreQueue;
// Caches for uid->username and gid->groupname lookups.
@property NSCache<NSNumber *, NSString *> *userNameMap;
@property NSCache<NSNumber *, NSString *> *groupNameMap;
@property NSDateFormatter *dateFormatter;
@end
@implementation SNTEventLog
@@ -62,222 +47,47 @@
return self;
}
- (void)saveDecisionDetails:(SNTCachedDecision *)cd {
dispatch_sync(_detailStoreQueue, ^{
_detailStore[@(cd.vnodeId)] = cd;
});
}
- (void)logFileModification:(santa_message_t)message {
NSString *action, *newpath;
NSString *path = @(message.path);
switch (message.action) {
case ACTION_NOTIFY_DELETE: {
action = @"DELETE";
break;
}
case ACTION_NOTIFY_EXCHANGE: {
action = @"EXCHANGE";
newpath = @(message.newpath);
break;
}
case ACTION_NOTIFY_LINK: {
action = @"LINK";
newpath = @(message.newpath);
break;
}
case ACTION_NOTIFY_RENAME: {
action = @"RENAME";
newpath = @(message.newpath);
break;
}
case ACTION_NOTIFY_WRITE: {
action = @"WRITE";
break;
}
default: action = @"UNKNOWN"; break;
}
// init the string with 2k capacity to avoid reallocs
NSMutableString *outStr = [NSMutableString stringWithCapacity:2048];
[outStr appendFormat:@"action=%@|path=%@", action, [self sanitizeString:path]];
if (newpath) {
[outStr appendFormat:@"|newpath=%@", [self sanitizeString:newpath]];
}
char ppath[PATH_MAX] = "(null)";
proc_pidpath(message.pid, ppath, PATH_MAX);
[outStr appendFormat:@"|pid=%d|ppid=%d|process=%s|processpath=%s|uid=%d|user=%@|gid=%d|group=%@",
message.pid, message.ppid, message.pname, ppath,
message.uid, [self nameForUID:message.uid],
message.gid, [self nameForGID:message.gid]];
LOGI(@"%@", outStr);
}
- (void)logDeniedExecution:(SNTCachedDecision *)cd withMessage:(santa_message_t)message {
[self logExecution:message withDecision:cd];
}
- (void)logAllowedExecution:(santa_message_t)message {
__block SNTCachedDecision *cd;
dispatch_sync(_detailStoreQueue, ^{
cd = _detailStore[@(message.vnode_id)];
});
[self logExecution:message withDecision:cd];
}
- (void)logExecution:(santa_message_t)message withDecision:(SNTCachedDecision *)cd {
NSString *d, *r;
BOOL logArgs = NO;
switch (cd.decision) {
case SNTEventStateAllowBinary:
d = @"ALLOW";
r = @"BINARY";
logArgs = YES;
break;
case SNTEventStateAllowCertificate:
d = @"ALLOW";
r = @"CERT";
logArgs = YES;
break;
case SNTEventStateAllowScope:
d = @"ALLOW";
r = @"SCOPE";
logArgs = YES;
break;
case SNTEventStateAllowUnknown:
d = @"ALLOW";
r = @"UNKNOWN";
logArgs = YES;
break;
case SNTEventStateBlockBinary:
d = @"DENY";
r = @"BINARY";
break;
case SNTEventStateBlockCertificate:
d = @"DENY";
r = @"CERT";
break;
case SNTEventStateBlockScope:
d = @"DENY";
r = @"SCOPE";
break;
case SNTEventStateBlockUnknown:
d = @"DENY";
r = @"UNKNOWN";
break;
default:
d = @"ALLOW";
r = @"NOTRUNNING";
logArgs = YES;
break;
}
// init the string with 4k capacity to avoid reallocs
NSMutableString *outLog = [[NSMutableString alloc] initWithCapacity:4096];
[outLog appendFormat:@"action=EXEC|decision=%@|reason=%@", d, r];
if (cd.decisionExtra) {
[outLog appendFormat:@"|explain=%@", cd.decisionExtra];
}
[outLog appendFormat:@"|sha256=%@", cd.sha256];
if (cd.certSHA256) {
[outLog appendFormat:@"|cert_sha256=%@|cert_cn=%@", cd.certSHA256,
[self sanitizeString:cd.certCommonName]];
}
if (cd.quarantineURL) {
[outLog appendFormat:@"|quarantine_url=%@", [self sanitizeString:cd.quarantineURL]];
}
NSString *mode;
switch ([[SNTConfigurator configurator] clientMode]) {
case SNTClientModeMonitor:
mode = @"M"; break;
case SNTClientModeLockdown:
mode = @"L"; break;
default:
mode = @"U"; break;
}
[outLog appendFormat:@"|pid=%d|ppid=%d|uid=%d|user=%@|gid=%d|group=%@|mode=%@|path=%@",
message.pid, message.ppid,
message.uid, [self nameForUID:message.uid],
message.gid, [self nameForGID:message.gid],
mode, [self sanitizeString:@(message.path)]];
// Check for app translocation by GateKeeper, and log original path if the case.
NSString *originalPath = [self originalPathForTranslocation:message];
if (originalPath) {
[outLog appendFormat:@"|origpath=%@", [self sanitizeString:originalPath]];
}
if (logArgs) {
[self addArgsForPid:message.pid toString:outLog];
}
LOGI(@"%@", outLog);
}
- (void)logDiskAppeared:(NSDictionary *)diskProperties {
NSString *dmgPath = @"";
NSString *serial = @"";
if ([diskProperties[@"DADeviceModel"] isEqual:@"Disk Image"]) {
dmgPath = [self diskImageForDevice:diskProperties[@"DADevicePath"]];
} else {
serial = [self serialForDevice:diskProperties[@"DADevicePath"]];
serial = [serial stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
}
NSString *model = [NSString stringWithFormat:@"%@ %@",
diskProperties[@"DADeviceVendor"] ?: @"",
diskProperties[@"DADeviceModel"] ?: @""];
model = [model stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
double appearance = [diskProperties[@"DAAppearanceTime"] doubleValue];
NSString *appearanceDateString =
[_dateFormatter stringFromDate:[NSDate dateWithTimeIntervalSinceReferenceDate:appearance]];
NSString *log =
@"action=DISKAPPEAR|mount=%@|volume=%@|bsdname=%@|fs=%@|"
@"model=%@|serial=%@|bus=%@|dmgpath=%@|appearance=%@";
LOGI(log,
[diskProperties[@"DAVolumePath"] path] ?: @"",
diskProperties[@"DAVolumeName"] ?: @"",
diskProperties[@"DAMediaBSDName"] ?: @"",
diskProperties[@"DAVolumeKind"] ?: @"",
model ?: @"",
serial,
diskProperties[@"DADeviceProtocol"] ?: @"",
dmgPath,
appearanceDateString);
[self doesNotRecognizeSelector:_cmd];
}
- (void)logDiskDisappeared:(NSDictionary *)diskProperties {
LOGI(@"action=DISKDISAPPEAR|mount=%@|volume=%@|bsdname=%@",
[diskProperties[@"DAVolumePath"] path] ?: @"",
diskProperties[@"DAVolumeName"] ?: @"",
diskProperties[@"DAMediaBSDName"]);
[self doesNotRecognizeSelector:_cmd];
}
- (void)logFileModification:(santa_message_t)message {
[self doesNotRecognizeSelector:_cmd];
}
- (void)logDeniedExecution:(SNTCachedDecision *)cd withMessage:(santa_message_t)message {
[self doesNotRecognizeSelector:_cmd];
}
- (void)logAllowedExecution:(santa_message_t)message {
[self doesNotRecognizeSelector:_cmd];
}
- (void)logBundleHashingEvents:(NSArray<SNTStoredEvent *> *)events {
for (SNTStoredEvent *event in events) {
LOGI(@"action=BUNDLE|sha256=%@|bundlehash=%@|bundlename=%@|bundleid=%@|bundlepath=%@|path=%@",
event.fileSHA256,
event.fileBundleHash,
event.fileBundleName,
event.fileBundleID,
event.fileBundlePath,
event.filePath);
}
[self doesNotRecognizeSelector:_cmd];
}
#pragma mark Helpers
- (void)writeLog:(NSString *)log {
[self doesNotRecognizeSelector:_cmd];
}
- (void)cacheDecision:(SNTCachedDecision *)cd {
dispatch_sync(self.detailStoreQueue, ^{
self.detailStore[@(cd.vnodeId)] = cd;
});
}
- (SNTCachedDecision *)cachedDecisionForMessage:(santa_message_t)message {
__block SNTCachedDecision *cd;
dispatch_sync(self.detailStoreQueue, ^{
cd = self.detailStore[@(message.vnode_id)];
});
return cd;
}
/**
Sanitizes a given string if necessary, otherwise returns the original.

View File

@@ -0,0 +1,18 @@
/// Copyright 2018 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 "SNTSyslogEventLog.h"
@interface SNTFileEventLog : SNTSyslogEventLog
@end

View File

@@ -0,0 +1,101 @@
/// Copyright 2018 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 "SNTFileEventLog.h"
#import "SNTConfigurator.h"
#import "SNTLogging.h"
#import "SNTStrengthify.h"
@interface SNTFileEventLog ()
@property NSFileHandle *fh;
@property(readonly, nonatomic) dispatch_queue_t q;
@property dispatch_source_t source;
@property(readonly, nonatomic) dispatch_source_t timer;
@property(readonly, nonatomic) NSString *path;
@property(readonly, nonatomic) NSMutableData *buffer;
@end
@implementation SNTFileEventLog
- (instancetype)init {
self = [super init];
if (self) {
_q = dispatch_queue_create("com.google.santa.file_event_log", DISPATCH_QUEUE_SERIAL);
_path = [[SNTConfigurator configurator] eventLogPath];
_fh = [self fileHandleForPath:_path];
[self watchLogFile];
// 8k buffer to batch logs for writing.
_buffer = [NSMutableData dataWithCapacity:8192];
// To avoid long lulls in the log being updated, flush the buffer every second.
_timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, _q);
dispatch_source_set_timer(_timer, dispatch_time(DISPATCH_TIME_NOW, 0), NSEC_PER_SEC * 1, 0);
WEAKIFY(self);
dispatch_source_set_event_handler(_timer, ^{
STRONGIFY(self);
[self flushBuffer];
});
dispatch_resume(_timer);
}
return self;
}
- (NSFileHandle *)fileHandleForPath:(NSString *)path {
NSFileManager *fm = [NSFileManager defaultManager];
if (![fm fileExistsAtPath:path]) {
[fm createFileAtPath:path contents:nil attributes:nil];
}
NSFileHandle *fh = [NSFileHandle fileHandleForWritingAtPath:path];
[fh seekToEndOfFile];
return fh;
}
- (void)watchLogFile {
if (self.source) {
dispatch_source_set_event_handler_f(self.source, NULL);
dispatch_source_cancel(self.source);
}
self.source = dispatch_source_create(DISPATCH_SOURCE_TYPE_VNODE,
self.fh.fileDescriptor,
DISPATCH_VNODE_DELETE | DISPATCH_VNODE_RENAME,
self.q);
WEAKIFY(self);
dispatch_source_set_event_handler(self.source, ^{
STRONGIFY(self);
[self.fh closeFile];
self.fh = [self fileHandleForPath:self.path];
[self watchLogFile];
});
dispatch_resume(self.source);
}
- (void)writeLog:(NSString *)log {
dispatch_async(self.q, ^{
NSString *dateString = [self.dateFormatter stringFromDate:[NSDate date]];
NSString *outLog = [NSString stringWithFormat:@"[%@] I santad: %@\n", dateString, log];
[self.buffer appendBytes:outLog.UTF8String
length:[outLog lengthOfBytesUsingEncoding:NSUTF8StringEncoding]];
// Avoid excessive calls to write() by batching logs.
if (self.buffer.length >= 4096) {
[self flushBuffer];
}
});
}
- (void)flushBuffer {
write(self.fh.fileDescriptor, self.buffer.bytes, self.buffer.length);
[self.buffer setLength:0];
}
@end

View File

@@ -0,0 +1,18 @@
/// Copyright 2018 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 "SNTEventLog.h"
@interface SNTSyslogEventLog : SNTEventLog
@end

View File

@@ -0,0 +1,242 @@
/// Copyright 2018 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 "SNTSyslogEventLog.h"
#import <libproc.h>
#import "SNTCachedDecision.h"
#import "SNTConfigurator.h"
#import "SNTLogging.h"
#import "SNTStoredEvent.h"
@implementation SNTSyslogEventLog
- (void)logFileModification:(santa_message_t)message {
NSString *action, *newpath;
NSString *path = @(message.path);
switch (message.action) {
case ACTION_NOTIFY_DELETE: {
action = @"DELETE";
break;
}
case ACTION_NOTIFY_EXCHANGE: {
action = @"EXCHANGE";
newpath = @(message.newpath);
break;
}
case ACTION_NOTIFY_LINK: {
action = @"LINK";
newpath = @(message.newpath);
break;
}
case ACTION_NOTIFY_RENAME: {
action = @"RENAME";
newpath = @(message.newpath);
break;
}
case ACTION_NOTIFY_WRITE: {
action = @"WRITE";
break;
}
default: action = @"UNKNOWN"; break;
}
// init the string with 2k capacity to avoid reallocs
NSMutableString *outStr = [NSMutableString stringWithCapacity:2048];
[outStr appendFormat:@"action=%@|path=%@", action, [self sanitizeString:path]];
if (newpath) {
[outStr appendFormat:@"|newpath=%@", [self sanitizeString:newpath]];
}
char ppath[PATH_MAX] = "(null)";
proc_pidpath(message.pid, ppath, PATH_MAX);
[outStr appendFormat:@"|pid=%d|ppid=%d|process=%s|processpath=%s|uid=%d|user=%@|gid=%d|group=%@",
message.pid, message.ppid, message.pname, ppath,
message.uid, [self nameForUID:message.uid],
message.gid, [self nameForGID:message.gid]];
[self writeLog:outStr];
}
- (void)logExecution:(santa_message_t)message withDecision:(SNTCachedDecision *)cd {
NSString *d, *r;
BOOL logArgs = NO;
switch (cd.decision) {
case SNTEventStateAllowBinary:
d = @"ALLOW";
r = @"BINARY";
logArgs = YES;
break;
case SNTEventStateAllowCertificate:
d = @"ALLOW";
r = @"CERT";
logArgs = YES;
break;
case SNTEventStateAllowScope:
d = @"ALLOW";
r = @"SCOPE";
logArgs = YES;
break;
case SNTEventStateAllowUnknown:
d = @"ALLOW";
r = @"UNKNOWN";
logArgs = YES;
break;
case SNTEventStateBlockBinary:
d = @"DENY";
r = @"BINARY";
break;
case SNTEventStateBlockCertificate:
d = @"DENY";
r = @"CERT";
break;
case SNTEventStateBlockScope:
d = @"DENY";
r = @"SCOPE";
break;
case SNTEventStateBlockUnknown:
d = @"DENY";
r = @"UNKNOWN";
break;
default:
d = @"ALLOW";
r = @"NOTRUNNING";
logArgs = YES;
break;
}
// init the string with 4k capacity to avoid reallocs
NSMutableString *outLog = [[NSMutableString alloc] initWithCapacity:4096];
[outLog appendFormat:@"action=EXEC|decision=%@|reason=%@", d, r];
if (cd.decisionExtra) {
[outLog appendFormat:@"|explain=%@", cd.decisionExtra];
}
[outLog appendFormat:@"|sha256=%@", cd.sha256];
if (cd.certSHA256) {
[outLog appendFormat:@"|cert_sha256=%@|cert_cn=%@", cd.certSHA256,
[self sanitizeString:cd.certCommonName]];
}
if (cd.quarantineURL) {
[outLog appendFormat:@"|quarantine_url=%@", [self sanitizeString:cd.quarantineURL]];
}
NSString *mode;
switch ([[SNTConfigurator configurator] clientMode]) {
case SNTClientModeMonitor:
mode = @"M"; break;
case SNTClientModeLockdown:
mode = @"L"; break;
default:
mode = @"U"; break;
}
[outLog appendFormat:@"|pid=%d|ppid=%d|uid=%d|user=%@|gid=%d|group=%@|mode=%@|path=%@",
message.pid, message.ppid,
message.uid, [self nameForUID:message.uid],
message.gid, [self nameForGID:message.gid],
mode, [self sanitizeString:@(message.path)]];
// Check for app translocation by GateKeeper, and log original path if the case.
NSString *originalPath = [self originalPathForTranslocation:message];
if (originalPath) {
[outLog appendFormat:@"|origpath=%@", [self sanitizeString:originalPath]];
}
if (logArgs) {
[self addArgsForPid:message.pid toString:outLog];
}
[self writeLog:outLog];
}
- (void)logDeniedExecution:(SNTCachedDecision *)cd withMessage:(santa_message_t)message {
[self logExecution:message withDecision:cd];
}
- (void)logAllowedExecution:(santa_message_t)message {
SNTCachedDecision *cd = [self cachedDecisionForMessage:message];
[self logExecution:message withDecision:cd];
}
- (void)logDiskAppeared:(NSDictionary *)diskProperties {
NSString *dmgPath = @"";
NSString *serial = @"";
if ([diskProperties[@"DADeviceModel"] isEqual:@"Disk Image"]) {
dmgPath = [self diskImageForDevice:diskProperties[@"DADevicePath"]];
} else {
serial = [self serialForDevice:diskProperties[@"DADevicePath"]];
serial = [serial stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
}
NSString *model = [NSString stringWithFormat:@"%@ %@",
diskProperties[@"DADeviceVendor"] ?: @"",
diskProperties[@"DADeviceModel"] ?: @""];
model = [model stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
double a = [diskProperties[@"DAAppearanceTime"] doubleValue];
NSString *appearanceDateString =
[self.dateFormatter stringFromDate:[NSDate dateWithTimeIntervalSinceReferenceDate:a]];
NSString *format =
@"action=DISKAPPEAR|mount=%@|volume=%@|bsdname=%@|fs=%@|"
@"model=%@|serial=%@|bus=%@|dmgpath=%@|appearance=%@";
NSString *outLog = [NSMutableString stringWithFormat:format,
[diskProperties[@"DAVolumePath"] path] ?: @"",
diskProperties[@"DAVolumeName"] ?: @"",
diskProperties[@"DAMediaBSDName"] ?: @"",
diskProperties[@"DAVolumeKind"] ?: @"",
model ?: @"",
serial,
diskProperties[@"DADeviceProtocol"] ?: @"",
dmgPath,
appearanceDateString];
[self writeLog:outLog];
}
- (void)logDiskDisappeared:(NSDictionary *)diskProperties {
NSString *format = @"action=DISKDISAPPEAR|mount=%@|volume=%@|bsdname=%@";
NSString *outLog = [NSMutableString stringWithFormat:format,
[diskProperties[@"DAVolumePath"] path] ?: @"",
diskProperties[@"DAVolumeName"] ?: @"",
diskProperties[@"DAMediaBSDName"]];
[self writeLog:outLog];
}
- (void)logBundleHashingEvents:(NSArray<SNTStoredEvent *> *)events {
for (SNTStoredEvent *event in events) {
NSString *format = @"action=DISKDISAPPEAR|mount=%@|volume=%@|bsdname=%@";
NSString *outLog = [NSMutableString stringWithFormat:format,
event.fileSHA256,
event.fileBundleHash,
event.fileBundleName,
event.fileBundleID,
event.fileBundlePath,
event.filePath];
[self writeLog:outLog];
}
}
- (void)writeLog:(NSString *)log {
LOGI(@"%@", log);
}
@end

View File

@@ -22,13 +22,14 @@
#import "SNTDatabaseController.h"
#import "SNTDriverManager.h"
#import "SNTDropRootPrivs.h"
#import "SNTEventLog.h"
#import "SNTEventTable.h"
#import "SNTExecutionController.h"
#import "SNTFileEventLog.h"
#import "SNTLogging.h"
#import "SNTNotificationQueue.h"
#import "SNTRuleTable.h"
#import "SNTSyncdQueue.h"
#import "SNTSyslogEventLog.h"
#import "SNTXPCConnection.h"
#import "SNTXPCControlInterface.h"
#import "SNTXPCNotifierInterface.h"
@@ -68,7 +69,16 @@
return nil;
}
_eventLog = [[SNTEventLog alloc] init];
// Choose an event logger.
SNTConfigurator *configurator = [SNTConfigurator configurator];
switch ([configurator eventLogType]) {
case SNTEventLogTypeSyslog:
_eventLog = [[SNTSyslogEventLog alloc] init];
break;
case SNTEventLogTypeFilelog:
_eventLog = [[SNTFileEventLog alloc] init];
break;
}
self.notQueue = [[SNTNotificationQueue alloc] init];
SNTSyncdQueue *syncdQueue = [[SNTSyncdQueue alloc] init];
@@ -80,7 +90,6 @@
// Listen for actionable config changes.
NSKeyValueObservingOptions bits = (NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld);
SNTConfigurator *configurator = [SNTConfigurator configurator];
[configurator addObserver:self
forKeyPath:NSStringFromSelector(@selector(clientMode))
options:bits
@@ -309,11 +318,17 @@ void diskDisappearedCallback(DADiskRef disk, void *context) {
- (void)syncBaseURLDidChange:(NSURL *)syncBaseURL {
if (syncBaseURL) {
LOGI(@"Starting santactl with new SyncBaseURL: %@", syncBaseURL);
[NSObject cancelPreviousPerformRequestsWithTarget:[SNTConfigurator configurator]
selector:@selector(clearSyncState)
object:nil];
[self startSyncd];
} else {
LOGI(@"SyncBaseURL removed, killing santactl pid: %i", self.syncdPID);
[self stopSyncd];
[[SNTConfigurator configurator] clearSyncState];
// Keep the syncState active for 10 min in case com.apple.ManagedClient is flapping.
[[SNTConfigurator configurator] performSelector:@selector(clearSyncState)
withObject:nil
afterDelay:600];
}
}

View File

@@ -225,6 +225,7 @@ double watchdogRAMPeak = 0;
bs.remoteInterface = [SNTXPCBundleServiceInterface bundleServiceInterface];
[bs resume];
[[bs remoteObjectProxy] setBundleNotificationListener:listener];
[bs invalidate];
}
#pragma mark syncd Ops

View File

@@ -117,9 +117,11 @@ static size_t kLargeBinarySize = 30 * 1024 * 1024;
// Get codesigning info about the file.
NSError *csError;
MOLCodesignChecker *csInfo = [[MOLCodesignChecker alloc] initWithBinaryPath:binInfo.path
error:&csError];
// Ignore codesigning if there are any errors with the signature.
MOLCodesignChecker *csInfo =
[[MOLCodesignChecker alloc] initWithBinaryPath:binInfo.path
fileDescriptor:binInfo.fileHandle.fileDescriptor
error:&csError];
// Ignore codesigning if there are any errors with the signature.
if (csError) csInfo = nil;
// Actually make the decision.
@@ -134,7 +136,7 @@ static size_t kLargeBinarySize = 30 * 1024 * 1024;
(SNTEventStateAllow & cd.decision) ? ACTION_RESPOND_ALLOW : ACTION_RESPOND_DENY;
// Save decision details for logging the execution later.
if (action == ACTION_RESPOND_ALLOW) [_eventLog saveDecisionDetails:cd];
if (action == ACTION_RESPOND_ALLOW) [_eventLog cacheDecision:cd];
// Send the decision to the kernel.
[_driverManager postToKernelAction:action forVnodeID:cd.vnodeId];

View File

@@ -47,7 +47,10 @@
self.mockCodesignChecker = OCMClassMock([MOLCodesignChecker class]);
OCMStub([self.mockCodesignChecker alloc]).andReturn(self.mockCodesignChecker);
OCMStub([self.mockCodesignChecker initWithBinaryPath:OCMOCK_ANY error:[OCMArg setTo:NULL]])
OCMStub([self.mockCodesignChecker initWithBinaryPath:OCMOCK_ANY
fileDescriptor:0
error:[OCMArg setTo:NULL]])
.andReturn(self.mockCodesignChecker);
self.mockConfigurator = OCMClassMock([SNTConfigurator class]);