mirror of
https://github.com/google/santa.git
synced 2026-01-15 01:08:12 -05:00
Compare commits
56 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6b0994a990 | ||
|
|
7dd616e891 | ||
|
|
c672edbe4d | ||
|
|
687ecc7097 | ||
|
|
b8882b4826 | ||
|
|
51de0b38a4 | ||
|
|
e0309c0482 | ||
|
|
5dbe86869d | ||
|
|
14a11279c7 | ||
|
|
df0ce42377 | ||
|
|
4c03411405 | ||
|
|
f020e18238 | ||
|
|
629bd4aff9 | ||
|
|
f20825a66c | ||
|
|
f098ca0d02 | ||
|
|
1f96f74f4d | ||
|
|
7a3a98c27a | ||
|
|
1130448cb9 | ||
|
|
d388e99c0e | ||
|
|
2baea9a6b4 | ||
|
|
0629625a9a | ||
|
|
a2d0acc761 | ||
|
|
28a6bce90f | ||
|
|
9058192ffe | ||
|
|
465b358271 | ||
|
|
7de585fe1d | ||
|
|
8479730c95 | ||
|
|
7102e2df4c | ||
|
|
c3bd99ff93 | ||
|
|
c560405a46 | ||
|
|
0c0fb28ccc | ||
|
|
a33fce942c | ||
|
|
369cd40ee5 | ||
|
|
577b431a41 | ||
|
|
75cf8acd33 | ||
|
|
d70983962b | ||
|
|
ff440984b0 | ||
|
|
c631155be7 | ||
|
|
6038930755 | ||
|
|
9edc119c62 | ||
|
|
269a94bf03 | ||
|
|
7f3e4d7468 | ||
|
|
eb89891cdd | ||
|
|
038b068370 | ||
|
|
d2017a59de | ||
|
|
3435b56a84 | ||
|
|
a812558d2d | ||
|
|
aefd85455e | ||
|
|
e42f1347b7 | ||
|
|
c7442a03d1 | ||
|
|
1eda8bdd9d | ||
|
|
c4d0628bdb | ||
|
|
d51ae66242 | ||
|
|
121dde6b8b | ||
|
|
98081b067d | ||
|
|
8cc9345b42 |
@@ -5,7 +5,6 @@ sudo: false
|
||||
osx_image: xcode7
|
||||
|
||||
before_install:
|
||||
- gem install activesupport
|
||||
- gem install cocoapods xcpretty
|
||||
- pod setup >/dev/null
|
||||
|
||||
|
||||
@@ -29,8 +29,8 @@ rake tests:kernel # only necessary if you're changing the kext code
|
||||
|
||||
All code submissions should try to match the surrounding code. Wherever possible,
|
||||
code should adhere to either the
|
||||
[Google Objective-C Style Guide](http://google-styleguide.googlecode.com/svn/trunk/objcguide.xml)
|
||||
or the [Google C++ Style Guide](http://google-styleguide.googlecode.com/svn/trunk/cppguide.html).
|
||||
[Google Objective-C Style Guide](https://google.github.io/styleguide/objcguide.xml)
|
||||
or the [Google C++ Style Guide](https://google.github.io/styleguide/cppguide.html).
|
||||
|
||||
### The small print
|
||||
Contributions made by corporations are covered by a different agreement than
|
||||
|
||||
64
Podfile
64
Podfile
@@ -2,47 +2,47 @@ platform :osx, "10.9"
|
||||
|
||||
inhibit_all_warnings!
|
||||
|
||||
def mol_pods
|
||||
target :Santa do
|
||||
pod 'MOLCertificate'
|
||||
pod 'MOLCodesignChecker'
|
||||
end
|
||||
|
||||
def fmdb_pod
|
||||
target :santad do
|
||||
pod 'FMDB'
|
||||
pod 'MOLCertificate'
|
||||
pod 'MOLCodesignChecker'
|
||||
end
|
||||
|
||||
# This is necessary to get FMDB to not NSLog stuff.
|
||||
post_install do |installer|
|
||||
installer.pods_project.targets.each do |target|
|
||||
target.build_configurations.each do |config|
|
||||
if config.name != 'Release' then
|
||||
break
|
||||
end
|
||||
target :santactl do
|
||||
pod 'FMDB'
|
||||
pod 'MOLAuthenticatingURLSession'
|
||||
pod 'MOLCertificate'
|
||||
pod 'MOLCodesignChecker'
|
||||
end
|
||||
|
||||
config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= ''
|
||||
config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] <<= "NDEBUG=1"
|
||||
target :LogicTests do
|
||||
pod 'FMDB'
|
||||
pod 'MOLAuthenticatingURLSession'
|
||||
pod 'MOLCertificate'
|
||||
pod 'MOLCodesignChecker'
|
||||
pod 'OCMock'
|
||||
end
|
||||
|
||||
post_install do |installer|
|
||||
installer.pods_project.targets.each do |target|
|
||||
target.build_configurations.each do |config|
|
||||
if config.name != 'Release' then
|
||||
break
|
||||
end
|
||||
|
||||
# This is necessary to get FMDB to not NSLog stuff.
|
||||
config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= ''
|
||||
config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] <<= "NDEBUG=1"
|
||||
|
||||
# Enable more compiler optimizations.
|
||||
config.build_settings['GCC_OPTIMIZATION_LEVEL'] = 'fast'
|
||||
config.build_settings['LLVM_LTO'] = 'YES'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
target :Santa do
|
||||
mol_pods
|
||||
end
|
||||
|
||||
target :santad do
|
||||
mol_pods
|
||||
fmdb_pod
|
||||
end
|
||||
|
||||
target :santactl do
|
||||
mol_pods
|
||||
fmdb_pod
|
||||
pod 'MOLAuthenticatingURLSession'
|
||||
end
|
||||
|
||||
target :LogicTests do
|
||||
mol_pods
|
||||
fmdb_pod
|
||||
pod 'MOLAuthenticatingURLSession'
|
||||
pod 'OCMock'
|
||||
end
|
||||
|
||||
@@ -4,7 +4,7 @@ PODS:
|
||||
- FMDB/standard (2.6.2)
|
||||
- MOLAuthenticatingURLSession (1.6):
|
||||
- MOLCertificate (~> 1.3)
|
||||
- MOLCertificate (1.4)
|
||||
- MOLCertificate (1.5)
|
||||
- MOLCodesignChecker (1.5):
|
||||
- MOLCertificate (~> 1.3)
|
||||
- OCMock (3.3)
|
||||
@@ -19,10 +19,10 @@ DEPENDENCIES:
|
||||
SPEC CHECKSUMS:
|
||||
FMDB: 854a0341b4726e53276f2a8996f06f1b80f9259a
|
||||
MOLAuthenticatingURLSession: f956240458fb24b61e5607d735948dc9babfb4e3
|
||||
MOLCertificate: da0bfeb5fa968bb4ac284569fa3f7d5f8f7abe23
|
||||
MOLCertificate: c39cae866d24d36fbc78032affff83d401b5384a
|
||||
MOLCodesignChecker: fc9c64147811d7b0d0739127003e0630dff9213a
|
||||
OCMock: d68685bde31f69cb61d518dcb39269080c78b5ed
|
||||
|
||||
PODFILE CHECKSUM: 3a8673334ffd78cdbd6576c85e6635248eb1b504
|
||||
PODFILE CHECKSUM: bc456d69693ca262c781dbbde40529a9474b84b5
|
||||
|
||||
COCOAPODS: 1.0.0
|
||||
COCOAPODS: 1.0.1
|
||||
|
||||
@@ -7,7 +7,7 @@ Santa [](h
|
||||
</a>
|
||||
</p>
|
||||
|
||||
Santa is a binary whitelisting/blacklisting system for OS X. It consists of
|
||||
Santa is a binary whitelisting/blacklisting system for macOS. It consists of
|
||||
a kernel extension that monitors for executions, a userland daemon that makes
|
||||
execution decisions based on the contents of a SQLite database, a GUI agent that
|
||||
notifies the user in case of a block decision and a command-line utility for
|
||||
@@ -136,7 +136,7 @@ and for security-reasons parts of Santa will not operate properly if not signed.
|
||||
|
||||
Kext Signing
|
||||
============
|
||||
Kernel extensions on OS X 10.9 and later must be signed using an Apple-provided
|
||||
Kernel extensions on macOS 10.9 and later must be signed using an Apple-provided
|
||||
Developer ID certificate with a kernel extension flag. Without it, the only way
|
||||
to load an extension is to enable kext-dev-mode or disable SIP, depending on the
|
||||
OS version.
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
0D0016A3192BCD3C005E7FCD /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0D9A7F3E1759330500035EB5 /* Foundation.framework */; };
|
||||
0D0016A6192BCD3C005E7FCD /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D0016A5192BCD3C005E7FCD /* main.m */; };
|
||||
0D0016A6192BCD3C005E7FCD /* main.mm in Sources */ = {isa = PBXBuildFile; fileRef = 0D0016A5192BCD3C005E7FCD /* main.mm */; };
|
||||
0D0016AE192BCD8C005E7FCD /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0D3AFBF718FB4C870087BCEE /* IOKit.framework */; };
|
||||
0D0A1EC3191998C900B8450F /* SNTCommandSyncRuleDownload.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D0A1EC2191998C900B8450F /* SNTCommandSyncRuleDownload.m */; };
|
||||
0D0A1EC6191AB9B000B8450F /* SNTCommandSyncPostflight.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D0A1EC5191AB9B000B8450F /* SNTCommandSyncPostflight.m */; };
|
||||
@@ -41,9 +41,11 @@
|
||||
0D202D1B1CDD465400A88F16 /* SNTCommandSyncState.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D416400191974F1006A356A /* SNTCommandSyncState.m */; };
|
||||
0D202D1E1CDD479400A88F16 /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 0D202D1D1CDD479400A88F16 /* libz.tbd */; };
|
||||
0D202D201CE4E90E00A88F16 /* sync_preflight_basic.json in Resources */ = {isa = PBXBuildFile; fileRef = 0D202D1F1CE4E90E00A88F16 /* sync_preflight_basic.json */; };
|
||||
0D202D251CE5071600A88F16 /* SantaCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 0D202D231CE5071600A88F16 /* SantaCache.h */; };
|
||||
0D20710E1A7C4A86008B0A9A /* SNTStoredEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DCD604A19105433006B445C /* SNTStoredEvent.m */; };
|
||||
0D28D53819D9F5910015C5EB /* SNTConfigurator.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D42D2B719D2042900955F08 /* SNTConfigurator.m */; };
|
||||
0D2CD4611A81C7B100C9C910 /* dn.plist in Resources */ = {isa = PBXBuildFile; fileRef = 0D2CD4601A81C7B100C9C910 /* dn.plist */; };
|
||||
0D2E1E631CEFA6C30039B2C4 /* SantaCacheTest.mm in Sources */ = {isa = PBXBuildFile; fileRef = 0D2E1E621CEFA6C30039B2C4 /* SantaCacheTest.mm */; };
|
||||
0D35BD9F18FD71CE00921A21 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0D9A7F3E1759330500035EB5 /* Foundation.framework */; };
|
||||
0D35BDA218FD71CE00921A21 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D35BDA118FD71CE00921A21 /* main.m */; };
|
||||
0D35BDAC18FD7CFD00921A21 /* SNTCommandController.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D35BDAB18FD7CFD00921A21 /* SNTCommandController.m */; };
|
||||
@@ -86,8 +88,6 @@
|
||||
0D6F12D819EC8822006B218E /* SecurityInterface.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0DCD5F771909C659006B445C /* SecurityInterface.framework */; };
|
||||
0D6FDC9618C93A020044685C /* SNTXPCConnection.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D6FDC9518C93A020044685C /* SNTXPCConnection.m */; };
|
||||
0D6FDC9718C93A020044685C /* SNTXPCConnection.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D6FDC9518C93A020044685C /* SNTXPCConnection.m */; };
|
||||
0D7A7AF3174FCF4C00B77646 /* SantaCachedDecision.cc in Sources */ = {isa = PBXBuildFile; fileRef = 0D7A7AF1174FCF4C00B77646 /* SantaCachedDecision.cc */; };
|
||||
0D7A7AF4174FCF4C00B77646 /* SantaCachedDecision.h in Headers */ = {isa = PBXBuildFile; fileRef = 0D7A7AF2174FCF4C00B77646 /* SantaCachedDecision.h */; };
|
||||
0D7D01871774F93A005DBAB4 /* SNTDriverManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D7D01861774F93A005DBAB4 /* SNTDriverManager.m */; };
|
||||
0D827E6519DF392E006EC811 /* SNTConfigurator.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D42D2B719D2042900955F08 /* SNTConfigurator.m */; };
|
||||
0D827E6719DF3C74006EC811 /* SNTCommandStatus.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D827E6619DF3C74006EC811 /* SNTCommandStatus.m */; };
|
||||
@@ -118,8 +118,6 @@
|
||||
0DB77FDB1CD14093004DF060 /* SNTBlockMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DB77FD71CCE824A004DF060 /* SNTBlockMessage.m */; };
|
||||
0DB77FFB1CD7AC5A004DF060 /* SNTCommandSyncConstants.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DEFB7BF1ACB28B000B92AAE /* SNTCommandSyncConstants.m */; };
|
||||
0DB8ACC1185662DC00FEF9C7 /* SNTApplication.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DB8ACC0185662DC00FEF9C7 /* SNTApplication.m */; };
|
||||
0DB98BFA1C1B9F3000B65DB1 /* SantaPIDAndPPID.cc in Sources */ = {isa = PBXBuildFile; fileRef = 0DB98BF81C1B9F3000B65DB1 /* SantaPIDAndPPID.cc */; };
|
||||
0DB98BFB1C1B9F3000B65DB1 /* SantaPIDAndPPID.h in Headers */ = {isa = PBXBuildFile; fileRef = 0DB98BF91C1B9F3000B65DB1 /* SantaPIDAndPPID.h */; };
|
||||
0DC5D86D191AED220078A5C0 /* SNTRuleTable.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DC5D86C191AED220078A5C0 /* SNTRuleTable.m */; };
|
||||
0DC5D86E191AED220078A5C0 /* SNTRuleTable.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DC5D86C191AED220078A5C0 /* SNTRuleTable.m */; };
|
||||
0DC5D871192160180078A5C0 /* SNTCommandSyncLogUpload.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DC5D870192160180078A5C0 /* SNTCommandSyncLogUpload.m */; };
|
||||
@@ -174,7 +172,12 @@
|
||||
29C490B1720D4FD576F93519 /* libPods-LogicTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 17D03B346587131C45A8DA67 /* libPods-LogicTests.a */; };
|
||||
2BA4AE89AA2447E29DA2E85C /* libPods-santactl.a in Frameworks */ = {isa = PBXBuildFile; fileRef = BE53E1EAE84D54E7FCB22FD5 /* libPods-santactl.a */; };
|
||||
4092327A1A51B66400A04527 /* SNTCommandRule.m in Sources */ = {isa = PBXBuildFile; fileRef = 409232791A51B65D00A04527 /* SNTCommandRule.m */; };
|
||||
5727587C816713451860B968 /* libPods-LogicTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 873978BCE4B0DBD2A89C99D1 /* libPods-LogicTests.a */; };
|
||||
8E9C0BF5D66552F66CC88CD9 /* libPods-Santa.a in Frameworks */ = {isa = PBXBuildFile; fileRef = B2B9044B79DD2E4DEC5D3B7A /* libPods-Santa.a */; };
|
||||
A60673DE57680AC450A3B0B2 /* libPods-santad.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 9BE438428F17C09C6A9D0802 /* libPods-santad.a */; };
|
||||
B6724720BE0366937D375488 /* libPods-santad.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 60A9B66BB0F7404D1F61D518 /* libPods-santad.a */; };
|
||||
C76614EC1D142D3C00D150C1 /* SNTCommandCheckCache.m in Sources */ = {isa = PBXBuildFile; fileRef = C76614EB1D142D3C00D150C1 /* SNTCommandCheckCache.m */; };
|
||||
F0AC4437ADEC6E17BDC3761F /* libPods-santactl.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 556108C12FC29E329D82D4CB /* libPods-santactl.a */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
@@ -252,7 +255,7 @@
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
0D0016A2192BCD3C005E7FCD /* KernelTests */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = KernelTests; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
0D0016A5192BCD3C005E7FCD /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
|
||||
0D0016A5192BCD3C005E7FCD /* main.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = main.mm; sourceTree = "<group>"; };
|
||||
0D0A1EC1191998C900B8450F /* SNTCommandSyncRuleDownload.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SNTCommandSyncRuleDownload.h; sourceTree = "<group>"; };
|
||||
0D0A1EC2191998C900B8450F /* SNTCommandSyncRuleDownload.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SNTCommandSyncRuleDownload.m; sourceTree = "<group>"; };
|
||||
0D0A1EC4191AB9B000B8450F /* SNTCommandSyncPostflight.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SNTCommandSyncPostflight.h; sourceTree = "<group>"; };
|
||||
@@ -265,6 +268,7 @@
|
||||
0D202D181CDD2EE500A88F16 /* SNTCommandSyncTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SNTCommandSyncTest.m; sourceTree = "<group>"; };
|
||||
0D202D1D1CDD479400A88F16 /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; };
|
||||
0D202D1F1CE4E90E00A88F16 /* sync_preflight_basic.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = sync_preflight_basic.json; sourceTree = "<group>"; };
|
||||
0D202D231CE5071600A88F16 /* SantaCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SantaCache.h; sourceTree = "<group>"; };
|
||||
0D260DAC18B68E12002A0B55 /* LogicTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = LogicTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
0D260DB118B68E12002A0B55 /* Tests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Tests-Info.plist"; sourceTree = "<group>"; };
|
||||
0D260DB718B68E12002A0B55 /* Tests-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Tests-Prefix.pch"; sourceTree = "<group>"; };
|
||||
@@ -272,6 +276,7 @@
|
||||
0D28E5E31926AFE400280F87 /* SNTKernelCommon.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SNTKernelCommon.h; sourceTree = "<group>"; };
|
||||
0D28E5E41926B55600280F87 /* santactl-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "santactl-Info.plist"; sourceTree = "<group>"; };
|
||||
0D2CD4601A81C7B100C9C910 /* dn.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = dn.plist; sourceTree = "<group>"; };
|
||||
0D2E1E621CEFA6C30039B2C4 /* SantaCacheTest.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = SantaCacheTest.mm; sourceTree = "<group>"; };
|
||||
0D35BD9E18FD71CE00921A21 /* santactl */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = santactl; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
0D35BDA118FD71CE00921A21 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
|
||||
0D35BDA418FD71CE00921A21 /* santactl-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "santactl-Prefix.pch"; sourceTree = "<group>"; };
|
||||
@@ -321,8 +326,6 @@
|
||||
0D668E8018D1121700E29A8B /* SNTMessageWindow.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SNTMessageWindow.m; sourceTree = "<group>"; };
|
||||
0D6FDC9418C93A020044685C /* SNTXPCConnection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SNTXPCConnection.h; sourceTree = "<group>"; };
|
||||
0D6FDC9518C93A020044685C /* SNTXPCConnection.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SNTXPCConnection.m; sourceTree = "<group>"; };
|
||||
0D7A7AF1174FCF4C00B77646 /* SantaCachedDecision.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SantaCachedDecision.cc; sourceTree = "<group>"; };
|
||||
0D7A7AF2174FCF4C00B77646 /* SantaCachedDecision.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SantaCachedDecision.h; sourceTree = "<group>"; };
|
||||
0D7D01851774F93A005DBAB4 /* SNTDriverManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SNTDriverManager.h; sourceTree = "<group>"; };
|
||||
0D7D01861774F93A005DBAB4 /* SNTDriverManager.m */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = SNTDriverManager.m; sourceTree = "<group>"; };
|
||||
0D827E6619DF3C74006EC811 /* SNTCommandStatus.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SNTCommandStatus.m; sourceTree = "<group>"; };
|
||||
@@ -351,8 +354,6 @@
|
||||
0DB8ACBF185662DC00FEF9C7 /* SNTApplication.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SNTApplication.h; sourceTree = "<group>"; };
|
||||
0DB8ACC0185662DC00FEF9C7 /* SNTApplication.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = SNTApplication.m; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objc; };
|
||||
0DB8ACE41858D73000FEF9C7 /* santad-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "santad-Info.plist"; sourceTree = "<group>"; };
|
||||
0DB98BF81C1B9F3000B65DB1 /* SantaPIDAndPPID.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SantaPIDAndPPID.cc; sourceTree = "<group>"; };
|
||||
0DB98BF91C1B9F3000B65DB1 /* SantaPIDAndPPID.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SantaPIDAndPPID.h; sourceTree = "<group>"; };
|
||||
0DC5D86C191AED220078A5C0 /* SNTRuleTable.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SNTRuleTable.m; sourceTree = "<group>"; };
|
||||
0DC5D86F192160180078A5C0 /* SNTCommandSyncLogUpload.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SNTCommandSyncLogUpload.h; sourceTree = "<group>"; };
|
||||
0DC5D870192160180078A5C0 /* SNTCommandSyncLogUpload.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SNTCommandSyncLogUpload.m; sourceTree = "<group>"; };
|
||||
@@ -399,13 +400,18 @@
|
||||
409232791A51B65D00A04527 /* SNTCommandRule.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SNTCommandRule.m; sourceTree = "<group>"; };
|
||||
4D9D2DDDCD92DBB948D38B11 /* 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>"; };
|
||||
4E43227BA5B261FF33141AFC /* Pods-LogicTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-LogicTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-LogicTests/Pods-LogicTests.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
556108C12FC29E329D82D4CB /* libPods-santactl.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-santactl.a"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
60A9B66BB0F7404D1F61D518 /* libPods-santad.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-santad.a"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
691189054F4E484D030CF831 /* Pods-santactl.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-santactl.debug.xcconfig"; path = "Pods/Target Support Files/Pods-santactl/Pods-santactl.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
7C9CC3CDF2609E78E6A9C601 /* Pods-santad.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-santad.release.xcconfig"; path = "Pods/Target Support Files/Pods-santad/Pods-santad.release.xcconfig"; sourceTree = "<group>"; };
|
||||
821428941753678DB772D761 /* Pods-LogicTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-LogicTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-LogicTests/Pods-LogicTests.release.xcconfig"; sourceTree = "<group>"; };
|
||||
873978BCE4B0DBD2A89C99D1 /* libPods-LogicTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-LogicTests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
87D1CEAEDF1FA6819A855559 /* libPods-Santa.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Santa.a"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
95B378553DCD86290341B8E4 /* Pods-santad.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-santad.debug.xcconfig"; path = "Pods/Target Support Files/Pods-santad/Pods-santad.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
9BE438428F17C09C6A9D0802 /* libPods-santad.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-santad.a"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
B2B9044B79DD2E4DEC5D3B7A /* libPods-Santa.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Santa.a"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
BE53E1EAE84D54E7FCB22FD5 /* libPods-santactl.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-santactl.a"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
C76614EB1D142D3C00D150C1 /* SNTCommandCheckCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SNTCommandCheckCache.m; sourceTree = "<group>"; };
|
||||
D227889DF327E7D3532FE00B /* Pods-Santa.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Santa.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Santa/Pods-Santa.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
@@ -427,6 +433,7 @@
|
||||
0D3AFBF618FB4C7E0087BCEE /* Cocoa.framework in Frameworks */,
|
||||
0D3AFBF818FB4C870087BCEE /* IOKit.framework in Frameworks */,
|
||||
29C490B1720D4FD576F93519 /* libPods-LogicTests.a in Frameworks */,
|
||||
5727587C816713451860B968 /* libPods-LogicTests.a in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -439,6 +446,7 @@
|
||||
0D35BDBD18FDA23600921A21 /* IOKit.framework in Frameworks */,
|
||||
0D35BD9F18FD71CE00921A21 /* Foundation.framework in Frameworks */,
|
||||
2BA4AE89AA2447E29DA2E85C /* libPods-santactl.a in Frameworks */,
|
||||
F0AC4437ADEC6E17BDC3761F /* libPods-santactl.a in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -451,6 +459,7 @@
|
||||
0D8C200C180F359A00CE2BF8 /* Security.framework in Frameworks */,
|
||||
0D385DB8180DE4A900418BC6 /* Cocoa.framework in Frameworks */,
|
||||
1C299D1C789489996FF9E081 /* libPods-Santa.a in Frameworks */,
|
||||
8E9C0BF5D66552F66CC88CD9 /* libPods-Santa.a in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -462,6 +471,7 @@
|
||||
0D4A5007176A4602004F63BF /* Security.framework in Frameworks */,
|
||||
0D9A7F3F1759330500035EB5 /* Foundation.framework in Frameworks */,
|
||||
A60673DE57680AC450A3B0B2 /* libPods-santad.a in Frameworks */,
|
||||
B6724720BE0366937D375488 /* libPods-santad.a in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -478,7 +488,7 @@
|
||||
0D0016A4192BCD3C005E7FCD /* KernelTests */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
0D0016A5192BCD3C005E7FCD /* main.m */,
|
||||
0D0016A5192BCD3C005E7FCD /* main.mm */,
|
||||
);
|
||||
path = KernelTests;
|
||||
sourceTree = "<group>";
|
||||
@@ -486,7 +496,9 @@
|
||||
0D260DAF18B68E12002A0B55 /* LogicTests */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
0D91BCB6174E8A7E00131A7D /* Frameworks */,
|
||||
0D260DB018B68E12002A0B55 /* Resources */,
|
||||
0D2E1E621CEFA6C30039B2C4 /* SantaCacheTest.mm */,
|
||||
0D202D181CDD2EE500A88F16 /* SNTCommandSyncTest.m */,
|
||||
0D41DAD31A7C28C800A890FE /* SNTEventTableTest.m */,
|
||||
0DD0D490194F9947005F27EB /* SNTExecutionControllerTest.m */,
|
||||
@@ -619,9 +631,9 @@
|
||||
children = (
|
||||
0DB77FDC1CD262F5004DF060 /* Source */,
|
||||
0D789F9F1940F26D0036F7C4 /* Tests */,
|
||||
0D91BCB6174E8A7E00131A7D /* Frameworks */,
|
||||
0D91BCB5174E8A7E00131A7D /* Products */,
|
||||
57575205DAC12A357F9EF899 /* Pods */,
|
||||
9A8F78FCF1FF5934C80FB9B4 /* Frameworks */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
@@ -656,21 +668,19 @@
|
||||
9BE438428F17C09C6A9D0802 /* libPods-santad.a */,
|
||||
);
|
||||
name = Frameworks;
|
||||
path = ../..;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
0D91BCB9174E8A7E00131A7D /* santa-driver */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
0D7A7AF2174FCF4C00B77646 /* SantaCachedDecision.h */,
|
||||
0D7A7AF1174FCF4C00B77646 /* SantaCachedDecision.cc */,
|
||||
0D202D231CE5071600A88F16 /* SantaCache.h */,
|
||||
0D4644C4182AF81700098690 /* SantaDecisionManager.h */,
|
||||
0D4644C3182AF81700098690 /* SantaDecisionManager.cc */,
|
||||
0D9A7F321759144800035EB5 /* SantaDriver.h */,
|
||||
0D9A7F311759144800035EB5 /* SantaDriver.cc */,
|
||||
0D9A7F361759148E00035EB5 /* SantaDriverClient.h */,
|
||||
0D9A7F351759148E00035EB5 /* SantaDriverClient.cc */,
|
||||
0DB98BF91C1B9F3000B65DB1 /* SantaPIDAndPPID.h */,
|
||||
0DB98BF81C1B9F3000B65DB1 /* SantaPIDAndPPID.cc */,
|
||||
0DA36C1F199EA46600A129D6 /* Resources */,
|
||||
);
|
||||
path = "santa-driver";
|
||||
@@ -760,6 +770,7 @@
|
||||
0DAF01141C1B794B00F5B6C3 /* Commands */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
C76614EB1D142D3C00D150C1 /* SNTCommandCheckCache.m */,
|
||||
0DCD5FBE1909D64A006B445C /* SNTCommandFileInfo.m */,
|
||||
0DE4C8A518FF3B1700466D04 /* SNTCommandFlushCache.m */,
|
||||
409232791A51B65D00A04527 /* SNTCommandRule.m */,
|
||||
@@ -797,6 +808,17 @@
|
||||
name = Pods;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
9A8F78FCF1FF5934C80FB9B4 /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
873978BCE4B0DBD2A89C99D1 /* libPods-LogicTests.a */,
|
||||
B2B9044B79DD2E4DEC5D3B7A /* libPods-Santa.a */,
|
||||
556108C12FC29E329D82D4CB /* libPods-santactl.a */,
|
||||
60A9B66BB0F7404D1F61D518 /* libPods-santad.a */,
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXHeadersBuildPhase section */
|
||||
@@ -804,8 +826,7 @@
|
||||
isa = PBXHeadersBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
0D7A7AF4174FCF4C00B77646 /* SantaCachedDecision.h in Headers */,
|
||||
0DB98BFB1C1B9F3000B65DB1 /* SantaPIDAndPPID.h in Headers */,
|
||||
0D202D251CE5071600A88F16 /* SantaCache.h in Headers */,
|
||||
0D4644C6182AF81700098690 /* SantaDecisionManager.h in Headers */,
|
||||
0D9A7F341759144800035EB5 /* SantaDriver.h in Headers */,
|
||||
0D9A7F381759148E00035EB5 /* SantaDriverClient.h in Headers */,
|
||||
@@ -835,13 +856,16 @@
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 0D260DBC18B68E12002A0B55 /* Build configuration list for PBXNativeTarget "LogicTests" */;
|
||||
buildPhases = (
|
||||
C88551472F6983D0B00880F8 /* 📦 Check Pods Manifest.lock */,
|
||||
376E230296F6EA7A4DA8BBF0 /* [CP] Check Pods Manifest.lock */,
|
||||
C88551472F6983D0B00880F8 /* [CP] Check Pods Manifest.lock */,
|
||||
0D673DAD18FC9017009C5B06 /* Delete existing coverage files */,
|
||||
0D260DA818B68E12002A0B55 /* Sources */,
|
||||
0D260DA918B68E12002A0B55 /* Frameworks */,
|
||||
0D260DAA18B68E12002A0B55 /* Resources */,
|
||||
1D12555F0F4EF323B11E40F9 /* 📦 Embed Pods Frameworks */,
|
||||
0C5C7A6AB763BCE7F760FAFF /* 📦 Copy Pods Resources */,
|
||||
1D12555F0F4EF323B11E40F9 /* [CP] Embed Pods Frameworks */,
|
||||
0C5C7A6AB763BCE7F760FAFF /* [CP] Copy Pods Resources */,
|
||||
14A598861D1307F88A43E84B /* 📦 Embed Pods Frameworks */,
|
||||
6695BC8CEF4D9E1DC8BCD43E /* 📦 Copy Pods Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
@@ -856,11 +880,13 @@
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 0D35BDA918FD71CE00921A21 /* Build configuration list for PBXNativeTarget "santactl" */;
|
||||
buildPhases = (
|
||||
EE6ABBFEC2708CE57EB1780A /* 📦 Check Pods Manifest.lock */,
|
||||
5F1504EA0D172767F2BCAAEB /* [CP] Check Pods Manifest.lock */,
|
||||
EE6ABBFEC2708CE57EB1780A /* [CP] Check Pods Manifest.lock */,
|
||||
0DD98E671A5DD02000A754C6 /* Update Version Info */,
|
||||
0D35BD9A18FD71CE00921A21 /* Sources */,
|
||||
0D35BD9B18FD71CE00921A21 /* Frameworks */,
|
||||
E50DD7319E04737B040B69EC /* 📦 Copy Pods Resources */,
|
||||
E50DD7319E04737B040B69EC /* [CP] Copy Pods Resources */,
|
||||
ED7B6914325B2B429B83C595 /* 📦 Copy Pods Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
@@ -875,13 +901,16 @@
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 0D385DE3180DE4A900418BC6 /* Build configuration list for PBXNativeTarget "Santa" */;
|
||||
buildPhases = (
|
||||
B34356D1FD4C8C6EF75F2FFE /* 📦 Check Pods Manifest.lock */,
|
||||
373591F801D7B22635DAD7A0 /* [CP] Check Pods Manifest.lock */,
|
||||
B34356D1FD4C8C6EF75F2FFE /* [CP] Check Pods Manifest.lock */,
|
||||
0DD98E681A5DD03E00A754C6 /* Update Version Info */,
|
||||
0D385DB2180DE4A900418BC6 /* Sources */,
|
||||
0D385DB3180DE4A900418BC6 /* Frameworks */,
|
||||
0D385DB4180DE4A900418BC6 /* Resources */,
|
||||
31CD7EDCDEBD95322ED67F63 /* 📦 Embed Pods Frameworks */,
|
||||
B3EB60284D47F89140F5A033 /* 📦 Copy Pods Resources */,
|
||||
31CD7EDCDEBD95322ED67F63 /* [CP] Embed Pods Frameworks */,
|
||||
B3EB60284D47F89140F5A033 /* [CP] Copy Pods Resources */,
|
||||
D21E717BD1BF6B67486244B1 /* 📦 Embed Pods Frameworks */,
|
||||
62408678C93447E3CE5B0C72 /* 📦 Copy Pods Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
@@ -918,11 +947,13 @@
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 0D9A7F471759330500035EB5 /* Build configuration list for PBXNativeTarget "santad" */;
|
||||
buildPhases = (
|
||||
A3D478EF1D48EA118AF176E9 /* 📦 Check Pods Manifest.lock */,
|
||||
44898C277E6A668A58B5E7A8 /* [CP] Check Pods Manifest.lock */,
|
||||
A3D478EF1D48EA118AF176E9 /* [CP] Check Pods Manifest.lock */,
|
||||
0DD98E661A5DCED300A754C6 /* Update Version Info */,
|
||||
0D9A7F391759330400035EB5 /* Sources */,
|
||||
0D9A7F3A1759330400035EB5 /* Frameworks */,
|
||||
435B0E246EE25ACC763D684C /* 📦 Copy Pods Resources */,
|
||||
435B0E246EE25ACC763D684C /* [CP] Copy Pods Resources */,
|
||||
B7DCDD8443739174F2B53ECF /* 📦 Copy Pods Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
@@ -939,7 +970,7 @@
|
||||
0D91BCA8174E8A6500131A7D /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastUpgradeCheck = 0720;
|
||||
LastUpgradeCheck = 0730;
|
||||
TargetAttributes = {
|
||||
0D260DAB18B68E12002A0B55 = {
|
||||
TestTargetID = 0D385DB5180DE4A900418BC6;
|
||||
@@ -1000,14 +1031,14 @@
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXShellScriptBuildPhase section */
|
||||
0C5C7A6AB763BCE7F760FAFF /* 📦 Copy Pods Resources */ = {
|
||||
0C5C7A6AB763BCE7F760FAFF /* [CP] Copy Pods Resources */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "📦 Copy Pods Resources";
|
||||
name = "[CP] Copy Pods Resources";
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
@@ -1108,7 +1139,7 @@
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "GIT_TAG=$(git describe --abbrev=0 --tags)\nsed -i '' \"s/TO.BE.FILLED/${GIT_TAG}/\" ${DERIVED_FILE_DIR}/santa-driver_info.c";
|
||||
};
|
||||
1D12555F0F4EF323B11E40F9 /* 📦 Embed Pods Frameworks */ = {
|
||||
14A598861D1307F88A43E84B /* 📦 Embed Pods Frameworks */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
@@ -1123,14 +1154,29 @@
|
||||
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-LogicTests/Pods-LogicTests-frameworks.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
31CD7EDCDEBD95322ED67F63 /* 📦 Embed Pods Frameworks */ = {
|
||||
1D12555F0F4EF323B11E40F9 /* [CP] Embed Pods Frameworks */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "📦 Embed Pods Frameworks";
|
||||
name = "[CP] Embed Pods Frameworks";
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-LogicTests/Pods-LogicTests-frameworks.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
31CD7EDCDEBD95322ED67F63 /* [CP] Embed Pods Frameworks */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "[CP] Embed Pods Frameworks";
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
@@ -1138,14 +1184,44 @@
|
||||
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Santa/Pods-Santa-frameworks.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
435B0E246EE25ACC763D684C /* 📦 Copy Pods Resources */ = {
|
||||
373591F801D7B22635DAD7A0 /* [CP] Check Pods Manifest.lock */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "📦 Copy Pods Resources";
|
||||
name = "[CP] Check Pods Manifest.lock";
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
376E230296F6EA7A4DA8BBF0 /* [CP] Check Pods Manifest.lock */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "[CP] Check Pods Manifest.lock";
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
435B0E246EE25ACC763D684C /* [CP] Copy Pods Resources */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "[CP] Copy Pods Resources";
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
@@ -1153,14 +1229,14 @@
|
||||
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-santad/Pods-santad-resources.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
A3D478EF1D48EA118AF176E9 /* 📦 Check Pods Manifest.lock */ = {
|
||||
44898C277E6A668A58B5E7A8 /* [CP] Check Pods Manifest.lock */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "📦 Check Pods Manifest.lock";
|
||||
name = "[CP] Check Pods Manifest.lock";
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
@@ -1168,14 +1244,14 @@
|
||||
shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
B34356D1FD4C8C6EF75F2FFE /* 📦 Check Pods Manifest.lock */ = {
|
||||
5F1504EA0D172767F2BCAAEB /* [CP] Check Pods Manifest.lock */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "📦 Check Pods Manifest.lock";
|
||||
name = "[CP] Check Pods Manifest.lock";
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
@@ -1183,7 +1259,7 @@
|
||||
shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
B3EB60284D47F89140F5A033 /* 📦 Copy Pods Resources */ = {
|
||||
62408678C93447E3CE5B0C72 /* 📦 Copy Pods Resources */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
@@ -1198,14 +1274,29 @@
|
||||
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Santa/Pods-Santa-resources.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
C88551472F6983D0B00880F8 /* 📦 Check Pods Manifest.lock */ = {
|
||||
6695BC8CEF4D9E1DC8BCD43E /* 📦 Copy Pods Resources */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "📦 Check Pods Manifest.lock";
|
||||
name = "📦 Copy Pods Resources";
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-LogicTests/Pods-LogicTests-resources.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
A3D478EF1D48EA118AF176E9 /* [CP] Check Pods Manifest.lock */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "[CP] Check Pods Manifest.lock";
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
@@ -1213,7 +1304,97 @@
|
||||
shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
E50DD7319E04737B040B69EC /* 📦 Copy Pods Resources */ = {
|
||||
B34356D1FD4C8C6EF75F2FFE /* [CP] Check Pods Manifest.lock */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "[CP] Check Pods Manifest.lock";
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
B3EB60284D47F89140F5A033 /* [CP] Copy Pods Resources */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "[CP] Copy Pods Resources";
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Santa/Pods-Santa-resources.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
B7DCDD8443739174F2B53ECF /* 📦 Copy Pods Resources */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "📦 Copy Pods Resources";
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-santad/Pods-santad-resources.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
C88551472F6983D0B00880F8 /* [CP] Check Pods Manifest.lock */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "[CP] Check Pods Manifest.lock";
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
D21E717BD1BF6B67486244B1 /* 📦 Embed Pods Frameworks */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "📦 Embed Pods Frameworks";
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Santa/Pods-Santa-frameworks.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
E50DD7319E04737B040B69EC /* [CP] Copy Pods Resources */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "[CP] Copy Pods Resources";
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-santactl/Pods-santactl-resources.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
ED7B6914325B2B429B83C595 /* 📦 Copy Pods Resources */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
@@ -1228,14 +1409,14 @@
|
||||
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-santactl/Pods-santactl-resources.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
EE6ABBFEC2708CE57EB1780A /* 📦 Check Pods Manifest.lock */ = {
|
||||
EE6ABBFEC2708CE57EB1780A /* [CP] Check Pods Manifest.lock */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "📦 Check Pods Manifest.lock";
|
||||
name = "[CP] Check Pods Manifest.lock";
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
@@ -1250,7 +1431,7 @@
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
0D0016A6192BCD3C005E7FCD /* main.m in Sources */,
|
||||
0D0016A6192BCD3C005E7FCD /* main.mm in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -1285,6 +1466,7 @@
|
||||
0D3AFBE718FB32CB0087BCEE /* SNTXPCConnectionTest.m in Sources */,
|
||||
0D9184B91CD2F32D0004E859 /* SNTCommandSyncStage.m in Sources */,
|
||||
0DCD605719115E54006B445C /* SNTDaemonControlController.m in Sources */,
|
||||
0D2E1E631CEFA6C30039B2C4 /* SantaCacheTest.mm in Sources */,
|
||||
0D41DAD41A7C28C800A890FE /* SNTEventTableTest.m in Sources */,
|
||||
0D3AFBEE18FB4C6C0087BCEE /* SNTApplication.m in Sources */,
|
||||
0DD0D48F194F78F8005F27EB /* SNTFileInfoTest.m in Sources */,
|
||||
@@ -1316,6 +1498,7 @@
|
||||
0D10BE871A0AABD600C0C944 /* SNTDropRootPrivs.m in Sources */,
|
||||
0DE4C8A618FF3B1700466D04 /* SNTCommandFlushCache.m in Sources */,
|
||||
4092327A1A51B66400A04527 /* SNTCommandRule.m in Sources */,
|
||||
C76614EC1D142D3C00D150C1 /* SNTCommandCheckCache.m in Sources */,
|
||||
0D416401191974F1006A356A /* SNTCommandSyncState.m in Sources */,
|
||||
0DC5D871192160180078A5C0 /* SNTCommandSyncLogUpload.m in Sources */,
|
||||
0DB77FDA1CD14092004DF060 /* SNTBlockMessage.m in Sources */,
|
||||
@@ -1359,8 +1542,6 @@
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
0D7A7AF3174FCF4C00B77646 /* SantaCachedDecision.cc in Sources */,
|
||||
0DB98BFA1C1B9F3000B65DB1 /* SantaPIDAndPPID.cc in Sources */,
|
||||
0D9A7F331759144800035EB5 /* SantaDriver.cc in Sources */,
|
||||
0D9A7F371759148E00035EB5 /* SantaDriverClient.cc in Sources */,
|
||||
0D4644C5182AF81700098690 /* SantaDecisionManager.cc in Sources */,
|
||||
@@ -1460,7 +1641,6 @@
|
||||
COPY_PHASE_STRIP = NO;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_PRECOMPILE_PREFIX_HEADER = YES;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"DEBUG=1",
|
||||
@@ -1534,7 +1714,6 @@
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
|
||||
GCC_GENERATE_TEST_COVERAGE_FILES = YES;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_PRECOMPILE_PREFIX_HEADER = YES;
|
||||
GCC_PREFIX_HEADER = "Tests/LogicTests/Resources/Tests-Prefix.pch";
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
@@ -1624,7 +1803,6 @@
|
||||
CREATE_INFOPLIST_SECTION_IN_BINARY = YES;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_PRECOMPILE_PREFIX_HEADER = YES;
|
||||
GCC_PREFIX_HEADER = "Source/santactl/Resources/santactl-Prefix.pch";
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
@@ -1701,7 +1879,6 @@
|
||||
COPY_PHASE_STRIP = NO;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_PRECOMPILE_PREFIX_HEADER = YES;
|
||||
GCC_PREFIX_HEADER = "Source/SantaGUI/Resources/Santa-Prefix.pch";
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
@@ -1769,6 +1946,8 @@
|
||||
CODE_SIGN_IDENTITY = "Mac Developer";
|
||||
ENABLE_TESTABILITY = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = c99;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
LLVM_LTO = YES;
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.9;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
PROVISIONING_PROFILE = "";
|
||||
@@ -1793,6 +1972,8 @@
|
||||
CODE_SIGN_IDENTITY = "Mac Developer";
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
GCC_C_LANGUAGE_STANDARD = c99;
|
||||
GCC_OPTIMIZATION_LEVEL = fast;
|
||||
LLVM_LTO = YES;
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.9;
|
||||
PROVISIONING_PROFILE = "";
|
||||
RUN_CLANG_STATIC_ANALYZER = YES;
|
||||
@@ -1820,7 +2001,6 @@
|
||||
COPY_PHASE_STRIP = NO;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_PRECOMPILE_PREFIX_HEADER = YES;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = "DEBUG=1";
|
||||
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
|
||||
@@ -1909,7 +2089,6 @@
|
||||
CREATE_INFOPLIST_SECTION_IN_BINARY = YES;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_PRECOMPILE_PREFIX_HEADER = YES;
|
||||
GCC_PREFIX_HEADER = "Source/santad/Resources/santad-Prefix.pch";
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0720"
|
||||
LastUpgradeVersion = "0730"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
@@ -27,7 +27,8 @@
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
codeCoverageEnabled = "YES">
|
||||
codeCoverageEnabled = "YES"
|
||||
enableAddressSanitizer = "YES">
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO">
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0720"
|
||||
LastUpgradeVersion = "0730"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0720"
|
||||
LastUpgradeVersion = "0730"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0720"
|
||||
LastUpgradeVersion = "0730"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0720"
|
||||
LastUpgradeVersion = "0730"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0720"
|
||||
LastUpgradeVersion = "0730"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0720"
|
||||
LastUpgradeVersion = "0730"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
<rect key="frame" x="18" y="65" width="444" height="60"/>
|
||||
<textFieldCell key="cell" sendsActionOnEndEditing="YES" alignment="center" id="CcT-ul-1eA">
|
||||
<font key="font" metaFont="system"/>
|
||||
<string key="title">Santa is an application whitelisting system for OS X.
|
||||
<string key="title">Santa is an application whitelisting system for macOS.
|
||||
|
||||
There are no user-configurable settings.</string>
|
||||
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="9532" systemVersion="15E65" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="10117" systemVersion="15F34" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
|
||||
<dependencies>
|
||||
<deployment identifier="macosx"/>
|
||||
<development version="6300" identifier="xcode"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="9532"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="10117"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<customObject id="-2" userLabel="File's Owner" customClass="SNTMessageWindowController">
|
||||
|
||||
@@ -123,7 +123,7 @@
|
||||
if (![key isEqualToString:@"event"]) {
|
||||
return [NSSet setWithObject:@"event"];
|
||||
} else {
|
||||
return nil;
|
||||
return [NSSet set];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -82,7 +82,7 @@ static NSString * const silencedNotificationsKey = @"SilencedNotifications";
|
||||
case SNTClientModeLockdown:
|
||||
un.informativeText = @"Switching into Lockdown mode";
|
||||
customMsg = [[SNTConfigurator configurator] modeNotificationLockdown];
|
||||
customMsg = [SNTBlockMessage stringFromHTML:customMsg];
|
||||
customMsg = [SNTBlockMessage stringFromHTML:customMsg];
|
||||
if (customMsg.length) un.informativeText = customMsg;
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -76,7 +76,17 @@ extern NSString *const NSURLQuarantinePropertiesKey WEAK_IMPORT_ATTRIBUTE;
|
||||
return nil;
|
||||
}
|
||||
|
||||
_fileHandle = [NSFileHandle fileHandleForReadingAtPath:_path];
|
||||
int fd = open([_path UTF8String], O_RDONLY | O_CLOEXEC);
|
||||
if (fd < 0) {
|
||||
if (error) {
|
||||
NSString *errStr = [NSString stringWithFormat:@"Unable to open file: %s", strerror(errno)];
|
||||
*error = [NSError errorWithDomain:@"com.google.santa.fileinfo"
|
||||
code:280
|
||||
userInfo:@{NSLocalizedDescriptionKey : errStr}];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
_fileHandle = [[NSFileHandle alloc] initWithFileDescriptor:fd closeOnDealloc:YES];
|
||||
|
||||
struct stat fileStat;
|
||||
fstat(_fileHandle.fileDescriptor, &fileStat);
|
||||
@@ -102,7 +112,9 @@ extern NSString *const NSURLQuarantinePropertiesKey WEAK_IMPORT_ATTRIBUTE;
|
||||
#pragma mark Hashing
|
||||
|
||||
- (void)hashSHA1:(NSString **)sha1 SHA256:(NSString **)sha256 {
|
||||
const int chunkSize = 4096;
|
||||
const int MAX_CHUNK_SIZE = 256 * 1024; // 256 KB
|
||||
const size_t chunkSize = _fileSize > MAX_CHUNK_SIZE ? MAX_CHUNK_SIZE : _fileSize;
|
||||
char chunk[chunkSize];
|
||||
|
||||
CC_SHA1_CTX c1;
|
||||
CC_SHA256_CTX c256;
|
||||
@@ -110,46 +122,59 @@ extern NSString *const NSURLQuarantinePropertiesKey WEAK_IMPORT_ATTRIBUTE;
|
||||
if (sha1) CC_SHA1_Init(&c1);
|
||||
if (sha256) CC_SHA256_Init(&c256);
|
||||
|
||||
for (uint64_t offset = 0; offset < self.fileSize; offset += chunkSize) {
|
||||
@autoreleasepool {
|
||||
int readSize = 0;
|
||||
if (offset + chunkSize > self.fileSize) {
|
||||
readSize = (int)(self.fileSize - offset);
|
||||
} else {
|
||||
readSize = chunkSize;
|
||||
}
|
||||
int fd = self.fileHandle.fileDescriptor;
|
||||
|
||||
NSData *chunk = [self safeSubdataWithRange:NSMakeRange(offset, readSize)];
|
||||
if (!chunk) {
|
||||
if (sha1) CC_SHA1_Final(NULL, &c1);
|
||||
if (sha256) CC_SHA256_Final(NULL, &c256);
|
||||
return;
|
||||
}
|
||||
fcntl(fd, F_RDAHEAD, 1);
|
||||
struct radvisory radv;
|
||||
radv.ra_offset = 0;
|
||||
const int MAX_ADVISORY_READ = 10 * 1024 * 1024;
|
||||
radv.ra_count = (int)_fileSize < MAX_ADVISORY_READ ? (int)_fileSize : MAX_ADVISORY_READ;
|
||||
fcntl(fd, F_RDADVISE, &radv);
|
||||
ssize_t bytesRead;
|
||||
|
||||
if (sha1) CC_SHA1_Update(&c1, chunk.bytes, readSize);
|
||||
if (sha256) CC_SHA256_Update(&c256, chunk.bytes, readSize);
|
||||
for (uint64_t offset = 0; offset < _fileSize;) {
|
||||
bytesRead = pread(fd, chunk, chunkSize, offset);
|
||||
if (bytesRead > 0) {
|
||||
if (sha1) CC_SHA1_Update(&c1, chunk, (CC_LONG)bytesRead);
|
||||
if (sha256) CC_SHA256_Update(&c256, chunk, (CC_LONG)bytesRead);
|
||||
offset += bytesRead;
|
||||
} else if (bytesRead == -1 && errno == EINTR) {
|
||||
continue;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// We turn off Read Ahead that we turned on
|
||||
fcntl(fd, F_RDAHEAD, 0);
|
||||
if (sha1) {
|
||||
unsigned char dgst[CC_SHA1_DIGEST_LENGTH];
|
||||
CC_SHA1_Final(dgst, &c1);
|
||||
|
||||
NSMutableString *buf = [[NSMutableString alloc] initWithCapacity:CC_SHA1_DIGEST_LENGTH * 2];
|
||||
for (int i = 0; i < CC_SHA1_DIGEST_LENGTH; ++i) {
|
||||
[buf appendFormat:@"%02x", (unsigned char)dgst[i]];
|
||||
}
|
||||
*sha1 = [buf copy];
|
||||
unsigned char digest[CC_SHA1_DIGEST_LENGTH];
|
||||
CC_SHA1_Final(digest, &c1);
|
||||
NSString *const SHA1FormatString =
|
||||
@"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x";
|
||||
*sha1 = [[NSString alloc]
|
||||
initWithFormat:SHA1FormatString, digest[0], digest[1], digest[2],
|
||||
digest[3], digest[4], digest[5], digest[6], digest[7],
|
||||
digest[8], digest[9], digest[10], digest[11], digest[12],
|
||||
digest[13], digest[14], digest[15], digest[16],
|
||||
digest[17], digest[18], digest[19]];
|
||||
}
|
||||
if (sha256) {
|
||||
unsigned char dgst[CC_SHA256_DIGEST_LENGTH];
|
||||
CC_SHA256_Final(dgst, &c256);
|
||||
unsigned char digest[CC_SHA256_DIGEST_LENGTH];
|
||||
CC_SHA256_Final(digest, &c256);
|
||||
NSString *const SHA256FormatString =
|
||||
@"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
|
||||
"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x";
|
||||
|
||||
NSMutableString *buf = [[NSMutableString alloc] initWithCapacity:CC_SHA256_DIGEST_LENGTH * 2];
|
||||
for (int i = 0; i < CC_SHA256_DIGEST_LENGTH; ++i) {
|
||||
[buf appendFormat:@"%02x", (unsigned char)dgst[i]];
|
||||
}
|
||||
*sha256 = [buf copy];
|
||||
*sha256 = [[NSString alloc]
|
||||
initWithFormat:SHA256FormatString, digest[0], digest[1], digest[2],
|
||||
digest[3], digest[4], digest[5], digest[6], digest[7],
|
||||
digest[8], digest[9], digest[10], digest[11], digest[12],
|
||||
digest[13], digest[14], digest[15], digest[16],
|
||||
digest[17], digest[18], digest[19], digest[20],
|
||||
digest[21], digest[22], digest[23], digest[24],
|
||||
digest[25], digest[26], digest[27], digest[28],
|
||||
digest[29], digest[30], digest[31]];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -199,18 +224,18 @@ extern NSString *const NSURLQuarantinePropertiesKey WEAK_IMPORT_ATTRIBUTE;
|
||||
|
||||
- (BOOL)isScript {
|
||||
const char *magic = (const char *)[[self safeSubdataWithRange:NSMakeRange(0, 2)] bytes];
|
||||
return (strncmp("#!", magic, 2) == 0);
|
||||
return (magic && memcmp("#!", magic, 2) == 0);
|
||||
}
|
||||
|
||||
- (BOOL)isXARArchive {
|
||||
const char *magic = (const char *)[[self safeSubdataWithRange:NSMakeRange(0, 4)] bytes];
|
||||
return (strncmp("xar!", magic, 4) == 0);
|
||||
return (magic && memcmp("xar!", magic, 4) == 0);
|
||||
}
|
||||
|
||||
- (BOOL)isDMG {
|
||||
NSUInteger last512 = self.fileSize - 512;
|
||||
const char *magic = (const char *)[[self safeSubdataWithRange:NSMakeRange(last512, 4)] bytes];
|
||||
return (magic && strncmp("koly", magic, 4) == 0);
|
||||
return (magic && memcmp("koly", magic, 4) == 0);
|
||||
}
|
||||
|
||||
#pragma mark Page Zero
|
||||
@@ -230,7 +255,7 @@ extern NSString *const NSURLQuarantinePropertiesKey WEAK_IMPORT_ATTRIBUTE;
|
||||
if (!lcData) return NO;
|
||||
|
||||
// This code assumes the __PAGEZERO is always the first load-command in the file.
|
||||
// Given that the OS X ABI says "the static linker creates a __PAGEZERO segment
|
||||
// Given that the macOS ABI says "the static linker creates a __PAGEZERO segment
|
||||
// as the first segment of an executable file." this should be OK.
|
||||
struct load_command *lc = (struct load_command *)[lcData bytes];
|
||||
if (lc->cmd == LC_SEGMENT) {
|
||||
@@ -273,9 +298,10 @@ extern NSString *const NSURLQuarantinePropertiesKey WEAK_IMPORT_ATTRIBUTE;
|
||||
// Check that the full path is at least 4-levels deep:
|
||||
// e.g: /Calendar.app/Contents/MacOS/Calendar
|
||||
NSArray *pathComponents = [self.path pathComponents];
|
||||
if ([pathComponents count] < 4) return nil;
|
||||
NSUInteger pathComponentsCount = pathComponents.count;
|
||||
if (pathComponentsCount < 4) return nil;
|
||||
|
||||
pathComponents = [pathComponents subarrayWithRange:NSMakeRange(0, [pathComponents count] - 3)];
|
||||
pathComponents = [pathComponents subarrayWithRange:NSMakeRange(0, pathComponentsCount - 3)];
|
||||
NSBundle *bndl = [NSBundle bundleWithPath:[NSString pathWithComponents:pathComponents]];
|
||||
if (bndl && [bndl objectForInfoDictionaryKey:@"CFBundleIdentifier"]) self.bundleRef = bndl;
|
||||
}
|
||||
@@ -445,7 +471,7 @@ extern NSString *const NSURLQuarantinePropertiesKey WEAK_IMPORT_ATTRIBUTE;
|
||||
if (!cmdData) return nil;
|
||||
struct segment_command_64 *lc = (struct segment_command_64 *)[cmdData bytes];
|
||||
if (lc->cmd == LC_SEGMENT || lc->cmd == LC_SEGMENT_64) {
|
||||
if (strncmp(lc->segname, "__TEXT", 6) == 0) {
|
||||
if (memcmp(lc->segname, "__TEXT", 6) == 0) {
|
||||
nsects = lc->nsects;
|
||||
offset += sz_segment;
|
||||
break;
|
||||
@@ -459,7 +485,7 @@ extern NSString *const NSURLQuarantinePropertiesKey WEAK_IMPORT_ATTRIBUTE;
|
||||
NSData *sectData = [self safeSubdataWithRange:NSMakeRange(offset, sz_section)];
|
||||
if (!sectData) return nil;
|
||||
struct section_64 *sect = (struct section_64 *)[sectData bytes];
|
||||
if (sect && strncmp(sect->sectname, "__info_plist", 12) == 0 && sect->size < 2000000) {
|
||||
if (sect && memcmp(sect->sectname, "__info_plist", 12) == 0 && sect->size < 2000000) {
|
||||
NSData *plistData = [self safeSubdataWithRange:NSMakeRange(sect->offset, sect->size)];
|
||||
if (!plistData) return nil;
|
||||
NSDictionary *plist;
|
||||
|
||||
@@ -52,7 +52,7 @@
|
||||
|
||||
dispatch_async(queue, ^{
|
||||
int fd = -1;
|
||||
while ((fd = open([self.filePath fileSystemRepresentation], O_EVTONLY)) < 0) {
|
||||
while ((fd = open([self.filePath fileSystemRepresentation], O_EVTONLY | O_CLOEXEC)) < 0) {
|
||||
usleep(200000); // wait 200ms
|
||||
}
|
||||
self.source = dispatch_source_create(DISPATCH_SOURCE_TYPE_VNODE, fd, mask, queue);
|
||||
@@ -80,7 +80,7 @@
|
||||
int fd = (int)dispatch_source_get_handle(self.source);
|
||||
if (fd > 0) close(fd);
|
||||
});
|
||||
|
||||
|
||||
dispatch_resume(self.source);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@ enum SantaDriverMethods {
|
||||
kSantaUserClientDenyBinary,
|
||||
kSantaUserClientClearCache,
|
||||
kSantaUserClientCacheCount,
|
||||
kSantaUserClientCheckCache,
|
||||
|
||||
// Any methods supported by the driver should be added above this line to
|
||||
// ensure this remains the count of methods.
|
||||
|
||||
@@ -21,6 +21,8 @@
|
||||
|
||||
#ifdef KERNEL
|
||||
|
||||
#include <IOKit/IOLib.h>
|
||||
|
||||
#ifdef DEBUG
|
||||
#define LOGD(...) IOLog("D santa-driver: " __VA_ARGS__); IOLog("\n")
|
||||
#else // DEBUG
|
||||
|
||||
@@ -52,7 +52,7 @@ void logMessage(LogLevel level, FILE *destination, NSString *format, ...) {
|
||||
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
NSString *s = [[NSString alloc] initWithFormat:format arguments:args];
|
||||
NSMutableString *s = [[NSMutableString alloc] initWithFormat:format arguments:args];
|
||||
va_end(args);
|
||||
|
||||
if (useSyslog) {
|
||||
@@ -86,6 +86,8 @@ void logMessage(LogLevel level, FILE *destination, NSString *format, ...) {
|
||||
|
||||
asl_log(client, NULL, syslogLevel, "%s %s: %s", levelName, binaryName, [s UTF8String]);
|
||||
} else {
|
||||
fprintf(destination, "%s\n", [s UTF8String]);
|
||||
[s appendString:@"\n"];
|
||||
size_t len = [s lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
|
||||
fwrite([s UTF8String], len, 1, destination);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,12 +40,12 @@
|
||||
@code
|
||||
[conn.remoteObjectProxy selectorInRemoteInterface];
|
||||
@endcode
|
||||
|
||||
|
||||
One advantage of the way that SNTXPCConnection works over using NSXPCConnection directly is that
|
||||
from the client-side once the resume method has finished, the connection is either valid or the
|
||||
invalidation handler will be called. Ordinarily, the connection doesn't actually get made until
|
||||
the first message is sent across it.
|
||||
|
||||
|
||||
@note messages are always delivered on a background thread!
|
||||
*/
|
||||
@interface SNTXPCConnection : NSObject<NSXPCListenerDelegate>
|
||||
@@ -79,7 +79,7 @@
|
||||
|
||||
/**
|
||||
Call when the properties of the object have been set-up and you're ready for connections.
|
||||
|
||||
|
||||
For clients, this call can take up to 2s to complete for connection to finish establishing though
|
||||
in basically all cases it will actually complete in a few milliseconds.
|
||||
*/
|
||||
@@ -97,7 +97,7 @@
|
||||
|
||||
/**
|
||||
A proxy to the object at the other end of the connection. (client)
|
||||
|
||||
|
||||
@note If the connection to the server failed, this will be nil, so you can safely send messages
|
||||
and rely on the invalidationHandler for handling the failure.
|
||||
*/
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
has one of these objects created which accept the message in the protocol
|
||||
and call the block provided during creation before replying.
|
||||
|
||||
This allows the server to reset the connection's exporteed interface and
|
||||
This allows the server to reset the connection's exported interface and
|
||||
object to the correct values after the client has sent the establishment message.
|
||||
*/
|
||||
@interface SNTXPCConnectionInterface : NSObject<SNTXPCConnectionProtocol>
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
/// limitations under the License.
|
||||
|
||||
#import "SNTCommonEnums.h"
|
||||
#import "SNTKernelCommon.h"
|
||||
|
||||
@class SNTRule;
|
||||
@class SNTStoredEvent;
|
||||
@@ -28,6 +29,7 @@
|
||||
///
|
||||
- (void)cacheCount:(void (^)(int64_t))reply;
|
||||
- (void)flushCache:(void (^)(BOOL))reply;
|
||||
- (void)checkCacheForVnodeID:(uint64_t)vnodeID withReply:(void (^)(santa_action_t))reply;
|
||||
|
||||
///
|
||||
/// Database ops
|
||||
|
||||
273
Source/santa-driver/SantaCache.h
Normal file
273
Source/santa-driver/SantaCache.h
Normal file
@@ -0,0 +1,273 @@
|
||||
/// Copyright 2016 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.
|
||||
|
||||
#ifndef SANTA__SANTA_DRIVER__SANTACACHE_H
|
||||
#define SANTA__SANTA_DRIVER__SANTACACHE_H
|
||||
|
||||
#include <libkern/OSAtomic.h>
|
||||
#include <libkern/OSTypes.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
#include "SNTKernelCommon.h"
|
||||
|
||||
#define likely(x) __builtin_expect((x), 1)
|
||||
#define unlikely(x) __builtin_expect((x), 0)
|
||||
|
||||
#ifdef KERNEL
|
||||
#include <IOKit/IOLib.h>
|
||||
#else // KERNEL
|
||||
// Support for unit testing.
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#define panic(args...) printf(args); printf("\n"); abort()
|
||||
#define IOMalloc malloc
|
||||
#define IOMallocAligned(sz, alignment) malloc(sz);
|
||||
#define IOFree(addr, sz) free(addr)
|
||||
#define IOFreeAligned(addr, sz) free(addr)
|
||||
#define OSTestAndSet OSAtomicTestAndSet
|
||||
#define OSTestAndClear(bit, addr) OSAtomicTestAndClear(bit, addr) == 0
|
||||
#define OSIncrementAtomic(addr) OSAtomicIncrement64((volatile int64_t *)addr)
|
||||
#define OSDecrementAtomic(addr) OSAtomicDecrement64((volatile int64_t *)addr)
|
||||
#endif // KERNEL
|
||||
|
||||
/**
|
||||
A somewhat simple, concurrent linked-list hash table intended for use in IOKit kernel extensions.
|
||||
Maps 64-bit unsigned integer keys to values.
|
||||
|
||||
Enforces a maximum size by clearing all entries if a new value
|
||||
is added that would go over the maximum size declared at creation.
|
||||
|
||||
The number of buckets is calculated as `maximum_size` / `per_bucket`
|
||||
rounded up to the next power of 2. Locking is done per-bucket.
|
||||
*/
|
||||
template<class T> class SantaCache {
|
||||
public:
|
||||
/**
|
||||
Initialize a newly created cache.
|
||||
|
||||
@param maximum_size The maximum number of entries in this cache. Once this
|
||||
number is reached all the entries will be purged.
|
||||
@param per_bucket The target number of entries in each bucket when cache is full.
|
||||
A higher number will result in better performance but higher memory usage.
|
||||
Cannot be higher than 64 to try and ensure buckets don't overflow.
|
||||
*/
|
||||
SantaCache(uint64_t maximum_size = 10000, uint8_t per_bucket = 5) {
|
||||
if (unlikely(per_bucket < 1)) per_bucket = 1;
|
||||
if (unlikely(per_bucket > 64)) per_bucket = 64;
|
||||
max_size_ = maximum_size;
|
||||
bucket_count_ = 1 << (32 - __builtin_clz(
|
||||
((uint32_t)max_size_ / per_bucket) - 1));
|
||||
buckets_ = (struct bucket *)IOMalloc(bucket_count_ * sizeof(struct bucket));
|
||||
bzero(buckets_, bucket_count_ * sizeof(struct bucket));
|
||||
}
|
||||
|
||||
/**
|
||||
Clear and free memory
|
||||
*/
|
||||
~SantaCache() {
|
||||
clear();
|
||||
IOFree(buckets_, bucket_count_ * sizeof(struct bucket));
|
||||
}
|
||||
|
||||
/**
|
||||
Get an element from the cache. Returns zero_ if item doesn't exist.
|
||||
*/
|
||||
T get(uint64_t key) {
|
||||
struct bucket *bucket = &buckets_[hash(key)];
|
||||
lock(bucket);
|
||||
struct entry *entry = (struct entry *)((uintptr_t)bucket->head - 1);
|
||||
while (entry != nullptr) {
|
||||
if (entry->key == key) {
|
||||
unlock(bucket);
|
||||
return entry->value;
|
||||
}
|
||||
entry = entry->next;
|
||||
}
|
||||
unlock(bucket);
|
||||
return zero_;
|
||||
}
|
||||
|
||||
/**
|
||||
Set an element in the cache.
|
||||
|
||||
@note If the cache is full when this is called, this will empty the cache before
|
||||
inserting the new value.
|
||||
|
||||
@return if an existing value was replaced, the previous value, otherwise zero_
|
||||
*/
|
||||
T set(uint64_t key, T value) {
|
||||
struct bucket *bucket = &buckets_[hash(key)];
|
||||
lock(bucket);
|
||||
struct entry *entry = (struct entry *)((uintptr_t)bucket->head - 1);
|
||||
struct entry *previous_entry = nullptr;
|
||||
while (entry != nullptr) {
|
||||
if (entry->key == key) {
|
||||
T existing_value = entry->value;
|
||||
entry->value = value;
|
||||
|
||||
if (value == zero_) {
|
||||
if (previous_entry != nullptr) {
|
||||
previous_entry->next = entry->next;
|
||||
} else {
|
||||
bucket->head = (struct entry *)((uintptr_t)entry->next + 1);
|
||||
}
|
||||
IOFreeAligned(entry, sizeof(struct entry));
|
||||
OSDecrementAtomic(&count_);
|
||||
}
|
||||
|
||||
unlock(bucket);
|
||||
return existing_value;
|
||||
}
|
||||
previous_entry = entry;
|
||||
entry = entry->next;
|
||||
}
|
||||
|
||||
// If value is zero_, we're clearing but there's nothing to clear
|
||||
// so we don't need to do anything else.
|
||||
if (value == zero_) {
|
||||
unlock(bucket);
|
||||
return zero_;
|
||||
}
|
||||
|
||||
// Check that adding this new item won't take the cache over its maximum size.
|
||||
if (count_ + 1 > max_size_) {
|
||||
unlock(bucket);
|
||||
lock(&clear_bucket_);
|
||||
// Check again in case clear has already run while waiting for lock
|
||||
if (count_ + 1 > max_size_) {
|
||||
clear();
|
||||
}
|
||||
lock(bucket);
|
||||
unlock(&clear_bucket_);
|
||||
}
|
||||
|
||||
// Allocate a new entry, set the key and value, then set the next pointer as the current
|
||||
// first entry in the bucket then make this new entry the first in the bucket.
|
||||
struct entry *new_entry = (struct entry *)IOMallocAligned(sizeof(struct entry), 2);
|
||||
new_entry->key = key;
|
||||
new_entry->value = value;
|
||||
new_entry->next = (struct entry *)((uintptr_t)bucket->head - 1);
|
||||
bucket->head = (struct entry *)((uintptr_t)new_entry + 1);
|
||||
OSIncrementAtomic(&count_);
|
||||
|
||||
unlock(bucket);
|
||||
return zero_;
|
||||
}
|
||||
|
||||
/**
|
||||
An alias for `set(key, zero_)`
|
||||
*/
|
||||
inline void remove(uint64_t key) {
|
||||
set(key, zero_);
|
||||
}
|
||||
|
||||
/**
|
||||
Remove all entries and free bucket memory.
|
||||
*/
|
||||
void clear() {
|
||||
for (uint32_t i = 0; i < bucket_count_; ++i) {
|
||||
struct bucket *bucket = &buckets_[i];
|
||||
// We grab the lock so nothing can use this bucket while we're erasing it
|
||||
// and never release it. It'll be 'released' when the bzero call happens
|
||||
// at the end of this function.
|
||||
lock(bucket);
|
||||
|
||||
// Free the bucket's entries, if there are any.
|
||||
struct entry *entry = (struct entry *)((uintptr_t)bucket->head - 1);
|
||||
while (entry != nullptr) {
|
||||
struct entry *next_entry = entry->next;
|
||||
IOFreeAligned(entry, sizeof(struct entry));
|
||||
entry = next_entry;
|
||||
}
|
||||
}
|
||||
|
||||
// Reset cache count, no atomicity needed as we hold all the bucket locks.
|
||||
count_ = 0;
|
||||
|
||||
// This resets all of the bucket counts and locks. Releasing the locks for
|
||||
// each bucket isn't really atomic here but each bucket will be zero'd
|
||||
// before the lock is released as the lock is the last thing in a bucket.
|
||||
bzero(buckets_, bucket_count_ * sizeof(struct bucket));
|
||||
}
|
||||
|
||||
/**
|
||||
Return number of entries currently in cache.
|
||||
*/
|
||||
inline uint64_t count() const {
|
||||
return count_;
|
||||
}
|
||||
|
||||
private:
|
||||
struct entry {
|
||||
uint64_t key;
|
||||
T value;
|
||||
struct entry *next;
|
||||
};
|
||||
|
||||
struct bucket {
|
||||
// The least significant bit of this pointer is always 0 (due to alignment),
|
||||
// so we utilize that bit as the lock for the bucket.
|
||||
struct entry *head;
|
||||
};
|
||||
|
||||
/**
|
||||
Lock a bucket. Spins until the lock is acquired.
|
||||
*/
|
||||
inline void lock(struct bucket *bucket) const {
|
||||
while (OSTestAndSet(7, (volatile uint8_t *)&bucket->head));
|
||||
}
|
||||
|
||||
/**
|
||||
Unlock a bucket. Panics if the lock wasn't locked.
|
||||
*/
|
||||
inline void unlock(struct bucket *bucket) const {
|
||||
if (unlikely(OSTestAndClear(7, (volatile uint8_t *)&bucket->head))) {
|
||||
panic("SantaCache::unlock(): Tried to unlock an unlocked lock");
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t count_ = 0;
|
||||
|
||||
uint64_t max_size_;
|
||||
uint32_t bucket_count_;
|
||||
|
||||
struct bucket *buckets_;
|
||||
|
||||
/**
|
||||
Holder for a 'zero' entry for the current type
|
||||
*/
|
||||
T zero_ = {};
|
||||
|
||||
/**
|
||||
Special bucket used when automatically clearing due to size
|
||||
to prevent two threads trying to clear at the same time and
|
||||
getting stuck.
|
||||
*/
|
||||
struct bucket clear_bucket_ = {};
|
||||
|
||||
/**
|
||||
Hash a key to determine which bucket it belongs in.
|
||||
|
||||
Multiplicative hash using a prime near to the golden ratio, per Knuth.
|
||||
This seems to have good bucket distribution generally and for the range of
|
||||
values we expect to see.
|
||||
*/
|
||||
inline uint64_t hash(uint64_t input) const {
|
||||
return (input * 11400714819323198549ul) % bucket_count_;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // SANTA__SANTA_DRIVER__SANTACACHE_H
|
||||
@@ -1,31 +0,0 @@
|
||||
/// Copyright 2015 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.
|
||||
|
||||
#include "SantaCachedDecision.h"
|
||||
|
||||
OSDefineMetaClassAndStructors(SantaCachedDecision, OSObject);
|
||||
|
||||
uint64_t SantaCachedDecision::getMicrosecs() const {
|
||||
return microsecs_;
|
||||
}
|
||||
|
||||
santa_action_t SantaCachedDecision::getAction() const {
|
||||
return action_;
|
||||
}
|
||||
|
||||
void SantaCachedDecision::setAction(
|
||||
const santa_action_t action, const uint64_t microsecs) {
|
||||
action_ = action;
|
||||
microsecs_ = microsecs;
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
/// Copyright 2015 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.
|
||||
|
||||
#ifndef SANTA__SANTA_DRIVER__SANTACACHEDDECISION_H
|
||||
#define SANTA__SANTA_DRIVER__SANTACACHEDDECISION_H
|
||||
|
||||
#include <libkern/c++/OSObject.h>
|
||||
|
||||
#include "SNTKernelCommon.h"
|
||||
|
||||
///
|
||||
/// An OSObject subclass to store a @c santa_action_t and a timestamp.
|
||||
/// Only OSObject subclasses can be inserted into an OSDictionary.
|
||||
///
|
||||
class SantaCachedDecision : public OSObject {
|
||||
OSDeclareDefaultStructors(SantaCachedDecision)
|
||||
|
||||
public:
|
||||
// Returns the time the action was last set.
|
||||
uint64_t getMicrosecs() const;
|
||||
|
||||
// Returns the set action.
|
||||
santa_action_t getAction() const;
|
||||
|
||||
// Sets the acion and receive time.
|
||||
void setAction(const santa_action_t action, const uint64_t microsecs);
|
||||
|
||||
private:
|
||||
santa_action_t action_;
|
||||
uint64_t microsecs_;
|
||||
};
|
||||
|
||||
#endif // SANTA__SANTA_DRIVER__SANTACACHEDDECISIONWRAPPER_H
|
||||
@@ -24,23 +24,20 @@ bool SantaDecisionManager::init() {
|
||||
|
||||
sdm_lock_grp_attr_ = lck_grp_attr_alloc_init();
|
||||
sdm_lock_grp_ = lck_grp_alloc_init("santa-locks", sdm_lock_grp_attr_);
|
||||
|
||||
sdm_lock_attr_ = lck_attr_alloc_init();
|
||||
|
||||
decision_dataqueue_lock_ = lck_mtx_alloc_init(sdm_lock_grp_, sdm_lock_attr_);
|
||||
log_dataqueue_lock_ = lck_mtx_alloc_init(sdm_lock_grp_, sdm_lock_attr_);
|
||||
cached_decisions_lock_ = lck_rw_alloc_init(sdm_lock_grp_, sdm_lock_attr_);
|
||||
vnode_pid_map_lock_ = lck_rw_alloc_init(sdm_lock_grp_, sdm_lock_attr_);
|
||||
|
||||
cached_decisions_ = OSDictionary::withCapacity(1000);
|
||||
vnode_pid_map_ = OSDictionary::withCapacity(1000);
|
||||
decision_cache_ = new SantaCache<uint64_t>(10000, 2);
|
||||
vnode_pid_map_ = new SantaCache<uint64_t>(2000, 5);
|
||||
|
||||
decision_dataqueue_ = IOSharedDataQueue::withEntries(kMaxDecisionQueueEvents,
|
||||
sizeof(santa_message_t));
|
||||
decision_dataqueue_ = IOSharedDataQueue::withEntries(
|
||||
kMaxDecisionQueueEvents, sizeof(santa_message_t));
|
||||
if (!decision_dataqueue_) return kIOReturnNoMemory;
|
||||
|
||||
log_dataqueue_ = IOSharedDataQueue::withEntries(kMaxLogQueueEvents,
|
||||
sizeof(santa_message_t));
|
||||
log_dataqueue_ = IOSharedDataQueue::withEntries(
|
||||
kMaxLogQueueEvents, sizeof(santa_message_t));
|
||||
if (!log_dataqueue_) return kIOReturnNoMemory;
|
||||
|
||||
client_pid_ = 0;
|
||||
@@ -49,15 +46,8 @@ bool SantaDecisionManager::init() {
|
||||
}
|
||||
|
||||
void SantaDecisionManager::free() {
|
||||
if (cached_decisions_lock_) {
|
||||
lck_rw_free(cached_decisions_lock_, sdm_lock_grp_);
|
||||
cached_decisions_lock_ = nullptr;
|
||||
}
|
||||
|
||||
if (vnode_pid_map_lock_) {
|
||||
lck_rw_free(vnode_pid_map_lock_, sdm_lock_grp_);
|
||||
vnode_pid_map_lock_ = nullptr;
|
||||
}
|
||||
delete decision_cache_;
|
||||
delete vnode_pid_map_;
|
||||
|
||||
if (decision_dataqueue_lock_) {
|
||||
lck_mtx_free(decision_dataqueue_lock_, sdm_lock_grp_);
|
||||
@@ -86,8 +76,6 @@ void SantaDecisionManager::free() {
|
||||
|
||||
OSSafeReleaseNULL(decision_dataqueue_);
|
||||
OSSafeReleaseNULL(log_dataqueue_);
|
||||
OSSafeReleaseNULL(cached_decisions_);
|
||||
OSSafeReleaseNULL(vnode_pid_map_);
|
||||
|
||||
super::free();
|
||||
}
|
||||
@@ -97,12 +85,12 @@ void SantaDecisionManager::free() {
|
||||
void SantaDecisionManager::ConnectClient(pid_t pid) {
|
||||
if (!pid) return;
|
||||
|
||||
client_pid_ = pid;
|
||||
|
||||
// Any decisions made while the daemon wasn't
|
||||
// connected should be cleared
|
||||
ClearCache();
|
||||
|
||||
client_pid_ = pid;
|
||||
|
||||
failed_decision_queue_requests_ = 0;
|
||||
failed_log_queue_requests_ = 0;
|
||||
}
|
||||
@@ -136,6 +124,7 @@ void SantaDecisionManager::DisconnectClient(bool itDied) {
|
||||
}
|
||||
|
||||
bool SantaDecisionManager::ClientConnected() const {
|
||||
if (client_pid_ <= 0) return false;
|
||||
auto p = proc_find(client_pid_);
|
||||
auto is_exiting = false;
|
||||
if (p) {
|
||||
@@ -168,14 +157,12 @@ IOMemoryDescriptor *SantaDecisionManager::GetLogMemoryDescriptor() const {
|
||||
#pragma mark Listener Control
|
||||
|
||||
kern_return_t SantaDecisionManager::StartListener() {
|
||||
vnode_listener_ = kauth_listen_scope(KAUTH_SCOPE_VNODE,
|
||||
vnode_scope_callback,
|
||||
reinterpret_cast<void *>(this));
|
||||
vnode_listener_ = kauth_listen_scope(
|
||||
KAUTH_SCOPE_VNODE, vnode_scope_callback, reinterpret_cast<void *>(this));
|
||||
if (!vnode_listener_) return kIOReturnInternalError;
|
||||
|
||||
fileop_listener_ = kauth_listen_scope(KAUTH_SCOPE_FILEOP,
|
||||
fileop_scope_callback,
|
||||
reinterpret_cast<void *>(this));
|
||||
fileop_listener_ = kauth_listen_scope(
|
||||
KAUTH_SCOPE_FILEOP, fileop_scope_callback, reinterpret_cast<void *>(this));
|
||||
if (!fileop_listener_) return kIOReturnInternalError;
|
||||
|
||||
LOGD("Listeners started.");
|
||||
@@ -206,113 +193,67 @@ kern_return_t SantaDecisionManager::StopListener() {
|
||||
#pragma mark Cache Management
|
||||
|
||||
void SantaDecisionManager::AddToCache(
|
||||
const char *identifier, santa_action_t decision, uint64_t microsecs) {
|
||||
if (cached_decisions_->getCount() > kMaxCacheSize) {
|
||||
// This could be made a _lot_ smarter, say only removing entries older
|
||||
// than a certain time period. However, with a kMaxCacheSize set
|
||||
// sufficiently large and a kMaxAllowCacheTimeMilliseconds set
|
||||
// sufficiently low, this should only ever occur if someone is purposefully
|
||||
// trying to make the cache grow.
|
||||
LOGI("Cache too large, flushing.");
|
||||
ClearCache();
|
||||
}
|
||||
uint64_t identifier, santa_action_t decision, uint64_t microsecs) {
|
||||
// Decision is stored in upper 8 bits, timestamp in remaining 56.
|
||||
uint64_t val = ((uint64_t)decision << 56) | (microsecs & 0xFFFFFFFFFFFFFF);
|
||||
|
||||
if (decision == ACTION_REQUEST_BINARY) {
|
||||
auto pending = new SantaCachedDecision();
|
||||
pending->setAction(ACTION_REQUEST_BINARY, 0);
|
||||
lck_rw_lock_exclusive(cached_decisions_lock_);
|
||||
cached_decisions_->setObject(identifier, pending);
|
||||
lck_rw_unlock_exclusive(cached_decisions_lock_);
|
||||
pending->release(); // it was retained when added to the dictionary
|
||||
} else {
|
||||
lck_rw_lock_exclusive(cached_decisions_lock_);
|
||||
auto pending = OSDynamicCast(
|
||||
SantaCachedDecision, cached_decisions_->getObject(identifier));
|
||||
if (pending) {
|
||||
pending->setAction(decision, microsecs);
|
||||
}
|
||||
lck_rw_unlock_exclusive(cached_decisions_lock_);
|
||||
// If a previous entry was not found and the new entry is not `REQUEST_BINARY`, remove the
|
||||
// existing entry. This is to prevent adding an ALLOW to the cache after a write has occurred.
|
||||
if (decision_cache_->set(identifier, val) == 0 && decision != ACTION_REQUEST_BINARY) {
|
||||
decision_cache_->remove(identifier);
|
||||
}
|
||||
}
|
||||
|
||||
void SantaDecisionManager::CacheCheck(const char *identifier) {
|
||||
lck_rw_lock_shared(cached_decisions_lock_);
|
||||
auto shouldInvalidate = (cached_decisions_->getObject(identifier) != nullptr);
|
||||
if (shouldInvalidate) {
|
||||
if (!lck_rw_lock_shared_to_exclusive(cached_decisions_lock_)) {
|
||||
// shared_to_exclusive will return false if a previous reader upgraded
|
||||
// and if that happens the lock will have been unlocked. If that happens,
|
||||
// which is rare, relock exclusively.
|
||||
lck_rw_lock_exclusive(cached_decisions_lock_);
|
||||
}
|
||||
cached_decisions_->removeObject(identifier);
|
||||
lck_rw_unlock_exclusive(cached_decisions_lock_);
|
||||
} else {
|
||||
lck_rw_unlock_shared(cached_decisions_lock_);
|
||||
}
|
||||
void SantaDecisionManager::RemoveFromCache(uint64_t identifier) {
|
||||
decision_cache_->remove(identifier);
|
||||
}
|
||||
|
||||
uint64_t SantaDecisionManager::CacheCount() const {
|
||||
return cached_decisions_->getCount();
|
||||
return decision_cache_->count();
|
||||
}
|
||||
|
||||
void SantaDecisionManager::ClearCache() {
|
||||
lck_rw_lock_exclusive(cached_decisions_lock_);
|
||||
cached_decisions_->flushCollection();
|
||||
lck_rw_unlock_exclusive(cached_decisions_lock_);
|
||||
decision_cache_->clear();
|
||||
}
|
||||
|
||||
#pragma mark Decision Fetching
|
||||
|
||||
santa_action_t SantaDecisionManager::GetFromCache(const char *identifier) {
|
||||
santa_action_t SantaDecisionManager::GetFromCache(uint64_t identifier) {
|
||||
auto result = ACTION_UNSET;
|
||||
uint64_t decision_time = 0;
|
||||
|
||||
lck_rw_lock_shared(cached_decisions_lock_);
|
||||
SantaCachedDecision *cached_decision = OSDynamicCast(
|
||||
SantaCachedDecision, cached_decisions_->getObject(identifier));
|
||||
if (cached_decision) {
|
||||
result = cached_decision->getAction();
|
||||
decision_time = cached_decision->getMicrosecs();
|
||||
}
|
||||
lck_rw_unlock_shared(cached_decisions_lock_);
|
||||
uint64_t cache_val = decision_cache_->get(identifier);
|
||||
if (cache_val == 0) return result;
|
||||
|
||||
// Decision is stored in upper 8 bits, timestamp in remaining 56.
|
||||
result = (santa_action_t)(cache_val >> 56);
|
||||
decision_time = (cache_val & ~(0xFF00000000000000));
|
||||
|
||||
if (RESPONSE_VALID(result)) {
|
||||
auto diff_time = GetCurrentUptime();
|
||||
|
||||
if (result == ACTION_RESPOND_ALLOW) {
|
||||
if ((kMaxAllowCacheTimeMilliseconds * 1000) > diff_time) {
|
||||
diff_time = 0;
|
||||
} else {
|
||||
diff_time -= (kMaxAllowCacheTimeMilliseconds * 1000);
|
||||
}
|
||||
} else if (result == ACTION_RESPOND_DENY) {
|
||||
if (result == ACTION_RESPOND_DENY) {
|
||||
auto diff_time = GetCurrentUptime();
|
||||
if ((kMaxDenyCacheTimeMilliseconds * 1000) > diff_time) {
|
||||
diff_time = 0;
|
||||
} else {
|
||||
diff_time -= (kMaxDenyCacheTimeMilliseconds * 1000);
|
||||
}
|
||||
}
|
||||
|
||||
if (decision_time < diff_time) {
|
||||
lck_rw_lock_exclusive(cached_decisions_lock_);
|
||||
cached_decisions_->removeObject(identifier);
|
||||
lck_rw_unlock_exclusive(cached_decisions_lock_);
|
||||
return ACTION_UNSET;
|
||||
if (decision_time < diff_time) {
|
||||
decision_cache_->remove(identifier);
|
||||
return ACTION_UNSET;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
santa_action_t SantaDecisionManager::GetFromDaemon(
|
||||
santa_message_t *message, const char *vnode_id_str) {
|
||||
santa_action_t SantaDecisionManager::GetFromDaemon(santa_message_t *message, uint64_t identifier) {
|
||||
auto return_action = ACTION_UNSET;
|
||||
|
||||
// Wait for the daemon to respond or die.
|
||||
do {
|
||||
// Add pending request to cache.
|
||||
AddToCache(vnode_id_str, ACTION_REQUEST_BINARY, 0);
|
||||
// Add pending request to cache, to be replaced by daemon with actual response
|
||||
AddToCache(identifier, ACTION_REQUEST_BINARY, 0);
|
||||
|
||||
// Send request to daemon...
|
||||
if (!PostToDecisionQueue(message)) {
|
||||
@@ -324,13 +265,13 @@ santa_action_t SantaDecisionManager::GetFromDaemon(
|
||||
client_pid_ = 0;
|
||||
}
|
||||
LOGE("Failed to queue request for %s.", message->path);
|
||||
CacheCheck(vnode_id_str);
|
||||
RemoveFromCache(identifier);
|
||||
return ACTION_ERROR;
|
||||
}
|
||||
|
||||
do {
|
||||
IOSleep(kRequestLoopSleepMilliseconds);
|
||||
return_action = GetFromCache(vnode_id_str);
|
||||
return_action = GetFromCache(identifier);
|
||||
} while (return_action == ACTION_REQUEST_BINARY && ClientConnected());
|
||||
} while (!RESPONSE_VALID(return_action) && ClientConnected());
|
||||
|
||||
@@ -338,7 +279,7 @@ santa_action_t SantaDecisionManager::GetFromDaemon(
|
||||
if (!RESPONSE_VALID(return_action)) {
|
||||
LOGE("Daemon process did not respond correctly. Allowing executions "
|
||||
"until it comes back. Executable path: %s", message->path);
|
||||
CacheCheck(vnode_id_str);
|
||||
RemoveFromCache(identifier);
|
||||
return ACTION_ERROR;
|
||||
}
|
||||
|
||||
@@ -353,7 +294,7 @@ santa_action_t SantaDecisionManager::FetchDecision(
|
||||
if (!ClientConnected()) return ACTION_RESPOND_ALLOW;
|
||||
|
||||
// Check to see if item is in cache
|
||||
auto return_action = GetFromCache(vnode_id_str);
|
||||
auto return_action = GetFromCache(vnode_id);
|
||||
|
||||
// If item was in cache return it.
|
||||
if (RESPONSE_VALID(return_action)) return return_action;
|
||||
@@ -370,7 +311,7 @@ santa_action_t SantaDecisionManager::FetchDecision(
|
||||
message->action = ACTION_REQUEST_BINARY;
|
||||
message->vnode_id = vnode_id;
|
||||
proc_name(message->ppid, message->pname, sizeof(message->pname));
|
||||
return_action = GetFromDaemon(message, vnode_id_str);
|
||||
return_action = GetFromDaemon(message, vnode_id);
|
||||
delete message;
|
||||
return return_action;
|
||||
}
|
||||
@@ -433,7 +374,7 @@ int SantaDecisionManager::VnodeCallback(const kauth_cred_t cred,
|
||||
// be the case if a file has been written to and flushed but not yet
|
||||
// closed.
|
||||
if (vnode_hasdirtyblks(vp)) {
|
||||
CacheCheck(vnode_str);
|
||||
RemoveFromCache(vnode_id);
|
||||
returnedAction = ACTION_RESPOND_DENY;
|
||||
}
|
||||
|
||||
@@ -441,16 +382,11 @@ int SantaDecisionManager::VnodeCallback(const kauth_cred_t cred,
|
||||
case ACTION_RESPOND_ALLOW: {
|
||||
auto proc = vfs_context_proc(ctx);
|
||||
if (proc) {
|
||||
auto pidWrapper = new SantaPIDAndPPID;
|
||||
pidWrapper->pid = proc_pid(proc);
|
||||
pidWrapper->ppid = proc_ppid(proc);
|
||||
lck_rw_lock_exclusive(vnode_pid_map_lock_);
|
||||
if (vnode_pid_map_->getCount() > 5000) {
|
||||
vnode_pid_map_->flushCollection();
|
||||
}
|
||||
vnode_pid_map_->setObject(vnode_str, pidWrapper);
|
||||
lck_rw_unlock_exclusive(vnode_pid_map_lock_);
|
||||
pidWrapper->release();
|
||||
pid_t pid = proc_pid(proc);
|
||||
pid_t ppid = proc_ppid(proc);
|
||||
// pid_t is 32-bit; pid is in upper 32 bits, ppid in lower.
|
||||
uint64_t val = ((uint64_t)pid << 32) | (ppid & 0xFFFFFFFF);
|
||||
vnode_pid_map_->set(vnode_id, val);
|
||||
}
|
||||
return KAUTH_RESULT_ALLOW;
|
||||
}
|
||||
@@ -476,25 +412,18 @@ void SantaDecisionManager::FileOpCallback(
|
||||
if (action == KAUTH_FILEOP_CLOSE) {
|
||||
char vnode_id_str[MAX_VNODE_ID_STR];
|
||||
snprintf(vnode_id_str, MAX_VNODE_ID_STR, "%llu", vnode_id);
|
||||
CacheCheck(vnode_id_str);
|
||||
RemoveFromCache(vnode_id);
|
||||
} else if (action == KAUTH_FILEOP_EXEC) {
|
||||
auto message = NewMessage(nullptr);
|
||||
message->vnode_id = vnode_id;
|
||||
message->action = ACTION_NOTIFY_EXEC;
|
||||
strlcpy(message->path, path, sizeof(message->path));
|
||||
|
||||
char vnode_str[MAX_VNODE_ID_STR];
|
||||
snprintf(vnode_str, MAX_VNODE_ID_STR, "%llu", vnode_id);
|
||||
|
||||
lck_rw_lock_shared(vnode_pid_map_lock_);
|
||||
auto pidWrapper = OSDynamicCast(
|
||||
SantaPIDAndPPID, vnode_pid_map_->getObject(vnode_str));
|
||||
if (pidWrapper) {
|
||||
message->pid = pidWrapper->pid;
|
||||
message->ppid = pidWrapper->ppid;
|
||||
uint64_t val = vnode_pid_map_->get(vnode_id);
|
||||
if (val) {
|
||||
// pid_t is 32-bit, so pid is in upper 32 bits, ppid in lower.
|
||||
message->pid = (val >> 32);
|
||||
message->ppid = (val & ~0xFFFFFFFF00000000);
|
||||
}
|
||||
lck_rw_unlock_shared(vnode_pid_map_lock_);
|
||||
|
||||
PostToLogQueue(message);
|
||||
delete message;
|
||||
return;
|
||||
@@ -504,7 +433,8 @@ void SantaDecisionManager::FileOpCallback(
|
||||
// Filter out modifications to locations that are definitely
|
||||
// not useful or made by santad.
|
||||
if (proc_selfpid() != client_pid_ &&
|
||||
!strprefix(path, "/.") && !strprefix(path, "/dev")) {
|
||||
!strprefix(path, "/.") &&
|
||||
!strprefix(path, "/dev")) {
|
||||
auto message = NewMessage(nullptr);
|
||||
strlcpy(message->path, path, sizeof(message->path));
|
||||
if (new_path) strlcpy(message->newpath, new_path, sizeof(message->newpath));
|
||||
@@ -526,7 +456,9 @@ void SantaDecisionManager::FileOpCallback(
|
||||
case KAUTH_FILEOP_DELETE:
|
||||
message->action = ACTION_NOTIFY_DELETE;
|
||||
break;
|
||||
default: delete message; return;
|
||||
default:
|
||||
delete message;
|
||||
return;
|
||||
}
|
||||
|
||||
PostToLogQueue(message);
|
||||
@@ -547,9 +479,6 @@ extern "C" int fileop_scope_callback(
|
||||
char *new_path = nullptr;
|
||||
|
||||
switch (action) {
|
||||
case KAUTH_FILEOP_CLOSE:
|
||||
if (!(arg2 & KAUTH_FILEOP_CLOSE_MODIFIED)) return KAUTH_RESULT_DEFER;
|
||||
// Intentional fall-through
|
||||
case KAUTH_FILEOP_DELETE:
|
||||
case KAUTH_FILEOP_EXEC:
|
||||
vp = reinterpret_cast<vnode_t>(arg0);
|
||||
@@ -576,20 +505,31 @@ extern "C" int fileop_scope_callback(
|
||||
extern "C" int vnode_scope_callback(
|
||||
kauth_cred_t credential, void *idata, kauth_action_t action,
|
||||
uintptr_t arg0, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3) {
|
||||
if (action & KAUTH_VNODE_ACCESS ||
|
||||
!(action & KAUTH_VNODE_EXECUTE) ||
|
||||
idata == nullptr) {
|
||||
if (action & KAUTH_VNODE_ACCESS || idata == nullptr) {
|
||||
return KAUTH_RESULT_DEFER;
|
||||
}
|
||||
|
||||
auto sdm = OSDynamicCast(
|
||||
SantaDecisionManager, reinterpret_cast<OSObject *>(idata));
|
||||
|
||||
sdm->IncrementListenerInvocations();
|
||||
int result = sdm->VnodeCallback(credential,
|
||||
reinterpret_cast<vfs_context_t>(arg0),
|
||||
reinterpret_cast<vnode_t>(arg1),
|
||||
reinterpret_cast<int *>(arg3));
|
||||
sdm->DecrementListenerInvocations();
|
||||
return result;
|
||||
if (action & KAUTH_VNODE_EXECUTE) {
|
||||
sdm->IncrementListenerInvocations();
|
||||
int result = sdm->VnodeCallback(credential,
|
||||
reinterpret_cast<vfs_context_t>(arg0),
|
||||
reinterpret_cast<vnode_t>(arg1),
|
||||
reinterpret_cast<int *>(arg3));
|
||||
sdm->DecrementListenerInvocations();
|
||||
return result;
|
||||
} else if (action & KAUTH_VNODE_WRITE_DATA) {
|
||||
vnode_t vp = reinterpret_cast<vnode_t>(arg1);
|
||||
if (vnode_vtype(vp) != VREG) return KAUTH_RESULT_DEFER;
|
||||
sdm->IncrementListenerInvocations();
|
||||
char path[MAXPATHLEN];
|
||||
int pathlen = MAXPATHLEN;
|
||||
vn_getpath(vp, path, &pathlen);
|
||||
sdm->FileOpCallback(KAUTH_FILEOP_CLOSE, vp, path, nullptr);
|
||||
sdm->DecrementListenerInvocations();
|
||||
}
|
||||
|
||||
return KAUTH_RESULT_DEFER;
|
||||
}
|
||||
|
||||
@@ -24,10 +24,9 @@
|
||||
#include <sys/proc.h>
|
||||
#include <sys/vnode.h>
|
||||
|
||||
#include "SantaCache.h"
|
||||
#include "SNTKernelCommon.h"
|
||||
#include "SNTLogging.h"
|
||||
#include "SantaCachedDecision.h"
|
||||
#include "SantaPIDAndPPID.h"
|
||||
|
||||
///
|
||||
/// SantaDecisionManager is responsible for intercepting Vnode execute actions
|
||||
@@ -40,178 +39,166 @@ class SantaDecisionManager : public OSObject {
|
||||
OSDeclareDefaultStructors(SantaDecisionManager);
|
||||
|
||||
public:
|
||||
/// Used for initialization after instantiation. Required because
|
||||
/// constructors cannot throw inside kernel-space.
|
||||
/// Used for initialization after instantiation.
|
||||
bool init() override;
|
||||
|
||||
/// Called automatically when retain count drops to 0.
|
||||
/// Called automatically when retain count drops to 0.
|
||||
void free() override;
|
||||
|
||||
/// Called by SantaDriverClient during connection to provide the shared
|
||||
/// dataqueue memory to the client.
|
||||
/**
|
||||
Called by SantaDriverClient during connection to provide the shared
|
||||
dataqueue memory to the client for the decision queue.
|
||||
*/
|
||||
IOMemoryDescriptor *GetDecisionMemoryDescriptor() const;
|
||||
|
||||
/**
|
||||
Called by SantaDriverClient during connection to provide the shared
|
||||
dataqueue memory to the client for the logging queue.
|
||||
*/
|
||||
IOMemoryDescriptor *GetLogMemoryDescriptor() const;
|
||||
|
||||
/// Called by SantaDriverClient when a client connects to the decision queue,
|
||||
/// providing the pid of the client process.
|
||||
/**
|
||||
Called by SantaDriverClient when a client connects to the decision queue,
|
||||
providing the pid of the client process.
|
||||
*/
|
||||
void ConnectClient(pid_t pid);
|
||||
|
||||
/// Called by SantaDriverClient when a client disconnects
|
||||
/// Called by SantaDriverClient when a client disconnects
|
||||
void DisconnectClient(bool itDied = false);
|
||||
|
||||
/// Returns whether a client is currently connected or not.
|
||||
/// Returns whether a client is currently connected or not.
|
||||
bool ClientConnected() const;
|
||||
|
||||
/// Sets the Mach port for notifying the decision queue.
|
||||
/// Sets the Mach port for notifying the decision queue.
|
||||
void SetDecisionPort(mach_port_t port);
|
||||
|
||||
/// Sets the Mach port for notifying the log queue.
|
||||
/// Sets the Mach port for notifying the log queue.
|
||||
void SetLogPort(mach_port_t port);
|
||||
|
||||
/// Starts the kauth listeners.
|
||||
/// Starts the kauth listeners.
|
||||
kern_return_t StartListener();
|
||||
|
||||
/// Stops the kauth listeners. After stopping new callback requests,
|
||||
/// waits until all current invocations have finished before clearing the
|
||||
/// cache and returning.
|
||||
/**
|
||||
Stops the kauth listeners. After stopping new callback requests, waits until all
|
||||
current invocations have finished before clearing the cache and returning.
|
||||
*/
|
||||
kern_return_t StopListener();
|
||||
|
||||
/// Adds a decision to the cache, with a timestamp.
|
||||
void AddToCache(const char *identifier,
|
||||
/// Adds a decision to the cache, with a timestamp.
|
||||
void AddToCache(uint64_t identifier,
|
||||
const santa_action_t decision,
|
||||
const uint64_t microsecs = GetCurrentUptime());
|
||||
|
||||
/// Checks to see if a given identifier is in the cache and removes it.
|
||||
void CacheCheck(const char *identifier);
|
||||
/// Fetches a response from the cache, first checking to see if the entry has expired.
|
||||
santa_action_t GetFromCache(uint64_t identifier);
|
||||
|
||||
/// Returns the number of entries in the cache.
|
||||
/// Checks to see if a given identifier is in the cache and removes it.
|
||||
void RemoveFromCache(uint64_t identifier);
|
||||
|
||||
/// Returns the number of entries in the cache.
|
||||
uint64_t CacheCount() const;
|
||||
|
||||
/// Clears the cache.
|
||||
/// Clears the cache.
|
||||
void ClearCache();
|
||||
|
||||
/// Increments the count of active callbacks pending.
|
||||
/// Increments the count of active callbacks pending.
|
||||
void IncrementListenerInvocations();
|
||||
|
||||
/// Decrements the count of active callbacks pending.
|
||||
/// Decrements the count of active callbacks pending.
|
||||
void DecrementListenerInvocations();
|
||||
|
||||
///
|
||||
/// Vnode Callback
|
||||
/// @param cred The kauth credential for this request.
|
||||
/// @param ctx The VFS context for this request.
|
||||
/// @param vp The Vnode for this request.
|
||||
/// @param errno A pointer to return an errno style error.
|
||||
/// @return int A valid KAUTH_RESULT_*.
|
||||
///
|
||||
/**
|
||||
Vnode Callback
|
||||
|
||||
@param cred The kauth credential for this request.
|
||||
@param ctx The VFS context for this request.
|
||||
@param vp The Vnode for this request.
|
||||
@param errno A pointer to return an errno style error.
|
||||
@return int A valid KAUTH_RESULT_*.
|
||||
*/
|
||||
int VnodeCallback(const kauth_cred_t cred, const vfs_context_t ctx,
|
||||
const vnode_t vp, int *errno);
|
||||
///
|
||||
/// FileOp Callback
|
||||
/// @param action The performed action
|
||||
/// @param vp The Vnode for this request. May be nullptr.
|
||||
/// @param path The path being operated on.
|
||||
/// @param new_path The target path for moves and links.
|
||||
///
|
||||
/**
|
||||
FileOp Callback
|
||||
|
||||
@param action The performed action
|
||||
@param vp The Vnode for this request. May be nullptr.
|
||||
@param path The path being operated on.
|
||||
@param new_path The target path for moves and links.
|
||||
*/
|
||||
void FileOpCallback(kauth_action_t action, const vnode_t vp,
|
||||
const char *path, const char *new_path);
|
||||
|
||||
protected:
|
||||
///
|
||||
/// The maximum number of milliseconds a cached deny message should be
|
||||
/// considered valid.
|
||||
///
|
||||
static const uint64_t kMaxDenyCacheTimeMilliseconds = 500;
|
||||
|
||||
///
|
||||
/// The maximum number of milliseconds a cached allow message should be
|
||||
/// considered valid.
|
||||
///
|
||||
static const uint64_t kMaxAllowCacheTimeMilliseconds = 1000 * 60 * 60 * 24;
|
||||
|
||||
///
|
||||
/// While waiting for a response from the daemon, this is the number of
|
||||
/// milliseconds to sleep for before checking the cache for a response.
|
||||
///
|
||||
/**
|
||||
While waiting for a response from the daemon, this is the number of
|
||||
milliseconds to sleep for before checking the cache for a response.
|
||||
*/
|
||||
static const uint32_t kRequestLoopSleepMilliseconds = 10;
|
||||
|
||||
///
|
||||
/// Maximum number of entries in the in-kernel cache.
|
||||
///
|
||||
/// The maximum number of milliseconds a cached deny message should be considered valid.
|
||||
static const uint64_t kMaxDenyCacheTimeMilliseconds = 500;
|
||||
|
||||
/// Maximum number of entries in the in-kernel cache.
|
||||
static const uint32_t kMaxCacheSize = 10000;
|
||||
|
||||
///
|
||||
/// Maximum number of PostToDecisionQueue failures to allow.
|
||||
///
|
||||
/// Maximum number of PostToDecisionQueue failures to allow.
|
||||
static const uint32_t kMaxDecisionQueueFailures = 10;
|
||||
|
||||
///
|
||||
/// The maximum number of messages can be kept in
|
||||
/// the decision data queue at any time.
|
||||
///
|
||||
/// The maximum number of messages can be kept in the decision data queue at any time.
|
||||
static const uint32_t kMaxDecisionQueueEvents = 512;
|
||||
|
||||
///
|
||||
/// The maximum number of messages can be kept
|
||||
/// in the logging data queue at any time.
|
||||
///
|
||||
/// The maximum number of messages can be kept in the logging data queue at any time.
|
||||
static const uint32_t kMaxLogQueueEvents = 1024;
|
||||
|
||||
/// Fetches a response from the cache, first checking to see if the
|
||||
/// entry has expired.
|
||||
santa_action_t GetFromCache(const char *identifier);
|
||||
/**
|
||||
Fetches a response from the daemon. Handles both daemon death
|
||||
and failure to post messages to the daemon.
|
||||
|
||||
/// Fetches a response from the daemon. Handles both daemon death
|
||||
/// and failure to post messages to the daemon.
|
||||
///
|
||||
/// @param message The message to send to the daemon
|
||||
/// @param identifier The vnode ID string for this request
|
||||
/// @return santa_action_t The response for this request
|
||||
///
|
||||
santa_action_t GetFromDaemon(santa_message_t *message,
|
||||
const char *identifier);
|
||||
@param message The message to send to the daemon
|
||||
@param identifier The vnode ID string for this request
|
||||
@return santa_action_t The response for this request
|
||||
*/
|
||||
santa_action_t GetFromDaemon(santa_message_t *message, uint64_t identifier);
|
||||
|
||||
///
|
||||
/// Fetches an execution decision for a file, first using the cache and then
|
||||
/// by sending a message to the daemon and waiting until a response arrives.
|
||||
/// If a daemon isn't connected, will allow execution and cache, logging
|
||||
/// the path to the executed file.
|
||||
///
|
||||
/// @param cred The credential for this request.
|
||||
/// @param vp The Vnode for this request.
|
||||
/// @param vnode_id The ID for this vnode.
|
||||
/// @param vnode_id_str A string representation of the above ID.
|
||||
///
|
||||
santa_action_t FetchDecision(const kauth_cred_t cred,
|
||||
const vnode_t vp,
|
||||
const uint64_t vnode_id,
|
||||
const char *vnode_id_str);
|
||||
/**
|
||||
Fetches an execution decision for a file, first using the cache and then
|
||||
by sending a message to the daemon and waiting until a response arrives.
|
||||
If a daemon isn't connected, will allow execution and cache, logging
|
||||
the path to the executed file.
|
||||
|
||||
///
|
||||
/// Posts the requested message to the decision data queue.
|
||||
///
|
||||
/// @param message The message to send
|
||||
/// @return bool true if sending was successful.
|
||||
///
|
||||
@param cred The credential for this request.
|
||||
@param vp The Vnode for this request.
|
||||
@param vnode_id The ID for this vnode.
|
||||
@param vnode_id_str A string representation of the above ID.
|
||||
*/
|
||||
santa_action_t FetchDecision(
|
||||
const kauth_cred_t cred, const vnode_t vp, const uint64_t vnode_id, const char *vnode_id_str);
|
||||
|
||||
/**
|
||||
Posts the requested message to the decision data queue.
|
||||
|
||||
@param message The message to send
|
||||
@return bool true if sending was successful.
|
||||
*/
|
||||
bool PostToDecisionQueue(santa_message_t *message);
|
||||
|
||||
///
|
||||
/// Posts the requested message to the logging data queue.
|
||||
///
|
||||
/// @param message The message to send
|
||||
/// @return bool true if sending was successful.
|
||||
///
|
||||
/**
|
||||
Posts the requested message to the logging data queue.
|
||||
|
||||
@param message The message to send
|
||||
@return bool true if sending was successful.
|
||||
*/
|
||||
bool PostToLogQueue(santa_message_t *message);
|
||||
|
||||
///
|
||||
/// Fetches the vnode_id for a given vnode.
|
||||
///
|
||||
/// @param ctx The VFS context to use.
|
||||
/// @param vp The Vnode to get the ID for
|
||||
/// @return uint64_t The Vnode ID as a 64-bit unsigned int.
|
||||
///
|
||||
static inline uint64_t GetVnodeIDForVnode(const vfs_context_t ctx,
|
||||
const vnode_t vp) {
|
||||
/**
|
||||
Fetches the vnode_id for a given vnode.
|
||||
|
||||
@param ctx The VFS context to use.
|
||||
@param vp The Vnode to get the ID for
|
||||
@return uint64_t The Vnode ID as a 64-bit unsigned int.
|
||||
*/
|
||||
static inline uint64_t GetVnodeIDForVnode(const vfs_context_t ctx, const vnode_t vp) {
|
||||
struct vnode_attr vap;
|
||||
VATTR_INIT(&vap);
|
||||
VATTR_WANTED(&vap, va_fsid);
|
||||
@@ -220,11 +207,12 @@ class SantaDecisionManager : public OSObject {
|
||||
return (((uint64_t)vap.va_fsid << 32) | vap.va_fileid);
|
||||
}
|
||||
|
||||
///
|
||||
/// Creates a new santa_message_t with some fields pre-filled.
|
||||
/// @param credential The kauth_cred_t for this action, if available.
|
||||
/// If nullptr, will get the credential for the current process.
|
||||
///
|
||||
/**
|
||||
Creates a new santa_message_t with some fields pre-filled.
|
||||
|
||||
@param credential The kauth_cred_t for this action, if available.
|
||||
If nullptr, will get the credential for the current process.
|
||||
*/
|
||||
static inline santa_message_t *NewMessage(kauth_cred_t credential) {
|
||||
bool should_release = false;
|
||||
if (credential == nullptr) {
|
||||
@@ -241,13 +229,13 @@ class SantaDecisionManager : public OSObject {
|
||||
if (should_release) {
|
||||
kauth_cred_unref(&credential);
|
||||
}
|
||||
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
///
|
||||
/// Returns the current system uptime in microseconds
|
||||
///
|
||||
/**
|
||||
Returns the current system uptime in microseconds
|
||||
*/
|
||||
static inline uint64_t GetCurrentUptime() {
|
||||
clock_sec_t sec;
|
||||
clock_usec_t usec;
|
||||
@@ -256,17 +244,15 @@ class SantaDecisionManager : public OSObject {
|
||||
}
|
||||
|
||||
private:
|
||||
SantaCache<uint64_t> *decision_cache_;
|
||||
SantaCache<uint64_t> *vnode_pid_map_;
|
||||
|
||||
lck_grp_t *sdm_lock_grp_;
|
||||
lck_grp_attr_t *sdm_lock_grp_attr_;
|
||||
|
||||
lck_attr_t *sdm_lock_attr_;
|
||||
lck_rw_t *cached_decisions_lock_;
|
||||
|
||||
lck_mtx_t *decision_dataqueue_lock_;
|
||||
lck_mtx_t *log_dataqueue_lock_;
|
||||
lck_rw_t *vnode_pid_map_lock_;
|
||||
|
||||
OSDictionary *cached_decisions_;
|
||||
OSDictionary *vnode_pid_map_;
|
||||
|
||||
IOSharedDataQueue *decision_dataqueue_;
|
||||
IOSharedDataQueue *log_dataqueue_;
|
||||
@@ -281,32 +267,44 @@ class SantaDecisionManager : public OSObject {
|
||||
kauth_listener_t fileop_listener_;
|
||||
};
|
||||
|
||||
///
|
||||
/// The kauth callback function for the Vnode scope
|
||||
/// @param actor's credentials
|
||||
/// @param data that was passed when the listener was registered
|
||||
/// @param action that was requested
|
||||
/// @param VFS context
|
||||
/// @param Vnode being operated on
|
||||
/// @param Parent Vnode. May be nullptr.
|
||||
/// @param Pointer to an errno-style error.
|
||||
///
|
||||
extern "C" int vnode_scope_callback(
|
||||
kauth_cred_t credential, void *idata, kauth_action_t action,
|
||||
uintptr_t arg0, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3);
|
||||
/**
|
||||
The kauth callback function for the Vnode scope
|
||||
|
||||
///
|
||||
/// The kauth callback function for the FileOp scope
|
||||
/// @param actor's credentials
|
||||
/// @param data that was passed when the listener was registered
|
||||
/// @param action that was requested
|
||||
/// @param depends on action, usually the vnode ref.
|
||||
/// @param depends on action.
|
||||
/// @param depends on action, usually 0.
|
||||
/// @param depends on action, usually 0.
|
||||
///
|
||||
@param actor's credentials
|
||||
@param data that was passed when the listener was registered
|
||||
@param action that was requested
|
||||
@param VFS context
|
||||
@param Vnode being operated on
|
||||
@param Parent Vnode. May be nullptr.
|
||||
@param Pointer to an errno-style error.
|
||||
*/
|
||||
extern "C" int vnode_scope_callback(
|
||||
kauth_cred_t credential,
|
||||
void *idata,
|
||||
kauth_action_t action,
|
||||
uintptr_t arg0,
|
||||
uintptr_t arg1,
|
||||
uintptr_t arg2,
|
||||
uintptr_t arg3);
|
||||
|
||||
/**
|
||||
The kauth callback function for the FileOp scope
|
||||
|
||||
@param actor's credentials
|
||||
@param data that was passed when the listener was registered
|
||||
@param action that was requested
|
||||
@param depends on action, usually the vnode ref.
|
||||
@param depends on action.
|
||||
@param depends on action, usually 0.
|
||||
@param depends on action, usually 0.
|
||||
*/
|
||||
extern "C" int fileop_scope_callback(
|
||||
kauth_cred_t credential, void *idata, kauth_action_t action,
|
||||
uintptr_t arg0, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3);
|
||||
kauth_cred_t credential,
|
||||
void *idata,
|
||||
kauth_action_t action,
|
||||
uintptr_t arg0,
|
||||
uintptr_t arg1,
|
||||
uintptr_t arg2,
|
||||
uintptr_t arg3);
|
||||
|
||||
#endif // SANTA__SANTA_DRIVER__SANTADECISIONMANAGER_H
|
||||
|
||||
@@ -130,10 +130,7 @@ IOReturn SantaDriverClient::static_open(
|
||||
}
|
||||
|
||||
IOReturn SantaDriverClient::allow_binary(const uint64_t vnode_id) {
|
||||
char vnode_id_str[21];
|
||||
snprintf(vnode_id_str, sizeof(vnode_id_str), "%llu", vnode_id);
|
||||
decisionManager->AddToCache(vnode_id_str, ACTION_RESPOND_ALLOW);
|
||||
|
||||
decisionManager->AddToCache(vnode_id, ACTION_RESPOND_ALLOW);
|
||||
return kIOReturnSuccess;
|
||||
}
|
||||
|
||||
@@ -149,10 +146,7 @@ IOReturn SantaDriverClient::static_allow_binary(
|
||||
}
|
||||
|
||||
IOReturn SantaDriverClient::deny_binary(const uint64_t vnode_id) {
|
||||
char vnode_id_str[21];
|
||||
snprintf(vnode_id_str, sizeof(vnode_id_str), "%llu", vnode_id);
|
||||
decisionManager->AddToCache(vnode_id_str, ACTION_RESPOND_DENY);
|
||||
|
||||
decisionManager->AddToCache(vnode_id, ACTION_RESPOND_DENY);
|
||||
return kIOReturnSuccess;
|
||||
}
|
||||
|
||||
@@ -193,6 +187,20 @@ IOReturn SantaDriverClient::static_cache_count(
|
||||
return target->cache_count(&(arguments->scalarOutput[0]));
|
||||
}
|
||||
|
||||
IOReturn SantaDriverClient::check_cache(uint64_t vnode_id, uint64_t *output) {
|
||||
*output = decisionManager->GetFromCache(vnode_id);
|
||||
return kIOReturnSuccess;
|
||||
}
|
||||
|
||||
IOReturn SantaDriverClient::static_check_cache(
|
||||
com_google_SantaDriverClient *target,
|
||||
void *reference,
|
||||
IOExternalMethodArguments *arguments) {
|
||||
if (!target) return kIOReturnBadArgument;
|
||||
return target->check_cache(reinterpret_cast<uint64_t>(*arguments->scalarInput),
|
||||
&(arguments->scalarOutput[0]));
|
||||
}
|
||||
|
||||
#pragma mark Method Resolution
|
||||
|
||||
IOReturn SantaDriverClient::externalMethod(
|
||||
@@ -203,7 +211,7 @@ IOReturn SantaDriverClient::externalMethod(
|
||||
void *reference) {
|
||||
/// Array of methods callable by clients. The order of these must match the
|
||||
/// order of the items in SantaDriverMethods in SNTKernelCommon.h
|
||||
IOExternalMethodDispatch sMethods[kSantaUserClientNMethods] = {
|
||||
static IOExternalMethodDispatch sMethods[kSantaUserClientNMethods] = {
|
||||
{
|
||||
reinterpret_cast<IOExternalMethodAction>(&SantaDriverClient::static_open),
|
||||
0, // input scalar
|
||||
@@ -242,6 +250,14 @@ IOReturn SantaDriverClient::externalMethod(
|
||||
0,
|
||||
1,
|
||||
0
|
||||
},
|
||||
{
|
||||
reinterpret_cast<IOExternalMethodAction>(
|
||||
&SantaDriverClient::static_check_cache),
|
||||
1,
|
||||
0,
|
||||
1,
|
||||
0
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -111,6 +111,14 @@ class com_google_SantaDriverClient : public IOUserClient {
|
||||
void *reference,
|
||||
IOExternalMethodArguments *arguments);
|
||||
|
||||
/// The daemon calls this to find out the status of a vnode_id in the cache.
|
||||
/// Output will be a santa_action_t.
|
||||
IOReturn check_cache(uint64_t vnode_id, uint64_t *output);
|
||||
static IOReturn static_check_cache(
|
||||
com_google_SantaDriverClient *target,
|
||||
void *reference,
|
||||
IOExternalMethodArguments *arguments);
|
||||
|
||||
private:
|
||||
com_google_SantaDriver *myProvider;
|
||||
SantaDecisionManager *decisionManager;
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
/// Copyright 2015 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.
|
||||
|
||||
#include "SantaPIDAndPPID.h"
|
||||
|
||||
OSDefineMetaClassAndStructors(SantaPIDAndPPID, OSObject);
|
||||
@@ -1,32 +0,0 @@
|
||||
/// Copyright 2015 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.
|
||||
|
||||
#ifndef SANTA__SANTA_DRIVER__SANTAPIDANDPPID_H
|
||||
#define SANTA__SANTA_DRIVER__SANTAPIDANDPPID_H
|
||||
|
||||
#include <libkern/c++/OSObject.h>
|
||||
|
||||
///
|
||||
/// An OSObject wrapper around a PID and PPID.
|
||||
/// Only OSObject subclasses can be inserted into an OSDictionary.
|
||||
///
|
||||
class SantaPIDAndPPID : public OSObject {
|
||||
OSDeclareDefaultStructors(SantaPIDAndPPID)
|
||||
|
||||
public:
|
||||
pid_t pid;
|
||||
pid_t ppid;
|
||||
};
|
||||
|
||||
#endif // SANTA__SANTA_DRIVER__SANTAPIDANDPPID_H
|
||||
71
Source/santactl/Commands/SNTCommandCheckCache.m
Normal file
71
Source/santactl/Commands/SNTCommandCheckCache.m
Normal file
@@ -0,0 +1,71 @@
|
||||
/// Copyright 2016 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 "SNTCommandController.h"
|
||||
|
||||
#import "SNTLogging.h"
|
||||
#import "SNTXPCConnection.h"
|
||||
#import "SNTXPCControlInterface.h"
|
||||
|
||||
#include <sys/stat.h>
|
||||
|
||||
@interface SNTCommandCheckCache : NSObject<SNTCommand>
|
||||
@end
|
||||
|
||||
@implementation SNTCommandCheckCache
|
||||
|
||||
#ifdef DEBUG
|
||||
REGISTER_COMMAND_NAME(@"checkcache")
|
||||
#endif
|
||||
|
||||
+ (BOOL)requiresRoot {
|
||||
return NO;
|
||||
}
|
||||
|
||||
+ (BOOL)requiresDaemonConn {
|
||||
return YES;
|
||||
}
|
||||
|
||||
+ (NSString *)shortHelpText {
|
||||
return @"Prints the status of a file in the kernel cache.";
|
||||
}
|
||||
|
||||
+ (NSString *)longHelpText {
|
||||
return (@"Checks the in-kernel cache for desired file.\n"
|
||||
@"Returns 0 if successful, 1 otherwise");
|
||||
}
|
||||
|
||||
+ (void)runWithArguments:(NSArray *)arguments daemonConnection:(SNTXPCConnection *)daemonConn {
|
||||
uint64_t vnodeID = [self vnodeIDForFile:arguments.firstObject];
|
||||
[[daemonConn remoteObjectProxy] checkCacheForVnodeID:vnodeID withReply:^(santa_action_t action) {
|
||||
if (action == ACTION_RESPOND_ALLOW) {
|
||||
LOGI(@"File exists in [whitelist] kernel cache");
|
||||
exit(0);
|
||||
} else if (action == ACTION_RESPOND_DENY) {
|
||||
LOGI(@"File exists in [blacklist] kernel cache");
|
||||
exit(0);
|
||||
} else if (action == ACTION_UNSET) {
|
||||
LOGE(@"File does not exist in cache");
|
||||
exit(1);
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
+ (uint64_t)vnodeIDForFile:(NSString *)path {
|
||||
struct stat fstat = {};
|
||||
stat(path.fileSystemRepresentation, &fstat);
|
||||
return (((uint64_t)fstat.st_dev << 32) | fstat.st_ino);
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -135,7 +135,7 @@ REGISTER_COMMAND_NAME(@"fileinfo")
|
||||
break;
|
||||
default: {
|
||||
NSString *val = [NSString stringWithFormat:@"Yes, but failed to validate (%ld)",
|
||||
error.code];
|
||||
error.code];
|
||||
[self printKey:@"Code-signed" value:val];
|
||||
break;
|
||||
}
|
||||
@@ -149,6 +149,7 @@ REGISTER_COMMAND_NAME(@"fileinfo")
|
||||
// Binary rule state
|
||||
__block SNTRule *r;
|
||||
dispatch_group_t group = dispatch_group_create();
|
||||
[daemonConn resume];
|
||||
dispatch_group_enter(group);
|
||||
[[daemonConn remoteObjectProxy] databaseBinaryRuleForSHA256:sha256 reply:^(SNTRule *rule) {
|
||||
if (rule) r = rule;
|
||||
@@ -161,7 +162,7 @@ REGISTER_COMMAND_NAME(@"fileinfo")
|
||||
if (!r && rule) r = rule;
|
||||
dispatch_group_leave(group);
|
||||
}];
|
||||
if (dispatch_group_wait(group, dispatch_time(DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC))) {
|
||||
if (dispatch_group_wait(group, dispatch_time(DISPATCH_TIME_NOW, 5 * NSEC_PER_SEC))) {
|
||||
[self printKey:@"Rule" value:@"Cannot communicate with daemon"];
|
||||
} else {
|
||||
NSString *output;
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
requestDict[kHostname] = [SNTSystemInfo longHostname];
|
||||
requestDict[kOSVer] = [SNTSystemInfo osVersion];
|
||||
requestDict[kOSBuild] = [SNTSystemInfo osBuild];
|
||||
requestDict[kSantaVer] = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"];
|
||||
requestDict[kSantaVer] = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"];
|
||||
requestDict[kPrimaryUser] = self.syncState.machineOwner;
|
||||
|
||||
dispatch_semaphore_t sema = dispatch_semaphore_create(0);
|
||||
|
||||
@@ -38,8 +38,8 @@
|
||||
- (BOOL)sync;
|
||||
|
||||
/**
|
||||
The URL for this stage.
|
||||
|
||||
The URL for this stage.
|
||||
|
||||
@return The NSURL for this stage.
|
||||
*/
|
||||
- (nonnull NSURL *)stageURL;
|
||||
@@ -49,7 +49,7 @@
|
||||
/**
|
||||
Creates an NSMutableURLRequest pointing at the URL for this stage and containing the JSON-encoded
|
||||
data passed in as a dictionary.
|
||||
|
||||
|
||||
@param dictionary The values to POST to the server.
|
||||
*/
|
||||
- (nullable NSMutableURLRequest *)requestWithDictionary:(nullable NSDictionary *)dictionary;
|
||||
@@ -58,7 +58,7 @@
|
||||
Perform the passed in request and attempt to parse the response as JSON into a dictionary.
|
||||
|
||||
@param request The request to perform
|
||||
@param timeout The number of seconds to allow the request to run before timing out.
|
||||
@param timeout The number of seconds to allow the request to run before timing out.
|
||||
|
||||
@return A populated dictionary if the response data was JSON, an empty dictionary if not and nil
|
||||
if the request failed for any reason.
|
||||
|
||||
@@ -77,13 +77,7 @@ static NSMutableDictionary *registeredCommands;
|
||||
exit(1);
|
||||
};
|
||||
[daemonConn resume];
|
||||
} else {
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
[daemonConn resume];
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
return daemonConn;
|
||||
}
|
||||
|
||||
|
||||
@@ -61,7 +61,7 @@
|
||||
@"WHERE (shasum=? OR shasum=?) AND state=?",
|
||||
self.santadCertSHA, self.launchdCertSHA, @(SNTRuleStateWhitelist)];
|
||||
if (ruleCount != 2) {
|
||||
if (version > 0) LOGE(@"Started without launchd/santad certificate rules in place!");
|
||||
if (version > 0) LOGE(@"Started without launchd/santad certificate rules in place!");
|
||||
[db executeUpdate:@"INSERT INTO rules (shasum, state, type) VALUES (?, ?, ?)",
|
||||
self.santadCertSHA, @(SNTRuleStateWhitelist), @(SNTRuleTypeCertificate)];
|
||||
[db executeUpdate:@"INSERT INTO rules (shasum, state, type) VALUES (?, ?, ?)",
|
||||
|
||||
@@ -146,7 +146,7 @@
|
||||
}
|
||||
case ACTION_REQUEST_BINARY: {
|
||||
dispatch_async(exec_queue, ^{
|
||||
[self.execController validateBinaryWithMessage:message];
|
||||
[_execController validateBinaryWithMessage:message];
|
||||
});
|
||||
break;
|
||||
}
|
||||
@@ -163,7 +163,7 @@
|
||||
dispatch_queue_t log_queue = dispatch_queue_create(
|
||||
"com.google.santad.log_queue", DISPATCH_QUEUE_CONCURRENT);
|
||||
dispatch_set_target_queue(
|
||||
log_queue, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0));
|
||||
log_queue, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0));
|
||||
|
||||
[self.driverManager listenForLogRequests:^(santa_message_t message) {
|
||||
@autoreleasepool {
|
||||
@@ -177,14 +177,14 @@
|
||||
NSRegularExpression *re = [[SNTConfigurator configurator] fileChangesRegex];
|
||||
NSString *path = @(message.path);
|
||||
if ([re numberOfMatchesInString:path options:0 range:NSMakeRange(0, path.length)]) {
|
||||
[self.eventLog logFileModification:message];
|
||||
[_eventLog logFileModification:message];
|
||||
}
|
||||
});
|
||||
break;
|
||||
}
|
||||
case ACTION_NOTIFY_EXEC: {
|
||||
dispatch_async(log_queue, ^{
|
||||
[self.eventLog logAllowedExecution:message];
|
||||
[_eventLog logAllowedExecution:message];
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -91,6 +91,10 @@ double watchdogRAMPeak = 0;
|
||||
reply([self.driverManager flushCache]);
|
||||
}
|
||||
|
||||
- (void)checkCacheForVnodeID:(uint64_t)vnodeID withReply:(void (^)(santa_action_t))reply {
|
||||
reply([self.driverManager checkCache:vnodeID]);
|
||||
}
|
||||
|
||||
#pragma mark Database ops
|
||||
|
||||
- (void)databaseRuleCounts:(void (^)(int64_t binary, int64_t certificate))reply {
|
||||
|
||||
@@ -55,4 +55,9 @@
|
||||
///
|
||||
- (BOOL)flushCache;
|
||||
|
||||
///
|
||||
/// Check the kernel cache for a VnodeID
|
||||
///
|
||||
-(santa_action_t)checkCache:(uint64_t)vnodeID;
|
||||
|
||||
@end
|
||||
|
||||
@@ -98,13 +98,9 @@ static const int MAX_DELAY = 15;
|
||||
withCallback:(void (^)(santa_message_t))callback {
|
||||
kern_return_t kr;
|
||||
|
||||
mach_port_t receivePort = 0;
|
||||
IODataQueueMemory *queueMemory = NULL;
|
||||
mach_vm_address_t address = 0;
|
||||
mach_vm_size_t size = 0;
|
||||
|
||||
// Allocate a mach port to receive notifactions from the IODataQueue
|
||||
if (!(receivePort = IODataQueueAllocateNotificationPort())) {
|
||||
mach_port_t receivePort = IODataQueueAllocateNotificationPort();
|
||||
if (receivePort == MACH_PORT_NULL) {
|
||||
LOGD(@"Failed to allocate notification port");
|
||||
return;
|
||||
}
|
||||
@@ -118,15 +114,16 @@ static const int MAX_DELAY = 15;
|
||||
}
|
||||
|
||||
// This will call clientMemoryForType() inside our user client class.
|
||||
kr = IOConnectMapMemory(self.connection, type, mach_task_self(),
|
||||
&address, &size, kIOMapAnywhere);
|
||||
mach_vm_address_t address = 0;
|
||||
mach_vm_size_t size = 0;
|
||||
kr = IOConnectMapMemory(self.connection, type, mach_task_self(), &address, &size, kIOMapAnywhere);
|
||||
if (kr != kIOReturnSuccess) {
|
||||
LOGD(@"Failed to map memory for type %d: %d", type, kr);
|
||||
mach_port_destroy(mach_task_self(), receivePort);
|
||||
return;
|
||||
}
|
||||
|
||||
queueMemory = (IODataQueueMemory *)address;
|
||||
IODataQueueMemory *queueMemory = (IODataQueueMemory *)address;
|
||||
|
||||
do {
|
||||
while (IODataQueueDataAvailable(queueMemory)) {
|
||||
@@ -151,14 +148,14 @@ static const int MAX_DELAY = 15;
|
||||
- (kern_return_t)postToKernelAction:(santa_action_t)action forVnodeID:(uint64_t)vnodeId {
|
||||
switch (action) {
|
||||
case ACTION_RESPOND_ALLOW:
|
||||
return IOConnectCallScalarMethod(self.connection,
|
||||
return IOConnectCallScalarMethod(_connection,
|
||||
kSantaUserClientAllowBinary,
|
||||
&vnodeId,
|
||||
1,
|
||||
0,
|
||||
0);
|
||||
case ACTION_RESPOND_DENY:
|
||||
return IOConnectCallScalarMethod(self.connection,
|
||||
return IOConnectCallScalarMethod(_connection,
|
||||
kSantaUserClientDenyBinary,
|
||||
&vnodeId,
|
||||
1,
|
||||
@@ -173,7 +170,7 @@ static const int MAX_DELAY = 15;
|
||||
uint32_t input_count = 1;
|
||||
uint64_t cache_count = 0;
|
||||
|
||||
IOConnectCallScalarMethod(self.connection,
|
||||
IOConnectCallScalarMethod(_connection,
|
||||
kSantaUserClientCacheCount,
|
||||
0,
|
||||
0,
|
||||
@@ -183,8 +180,21 @@ static const int MAX_DELAY = 15;
|
||||
}
|
||||
|
||||
- (BOOL)flushCache {
|
||||
return IOConnectCallScalarMethod(self.connection,
|
||||
return IOConnectCallScalarMethod(_connection,
|
||||
kSantaUserClientClearCache, 0, 0, 0, 0) == KERN_SUCCESS;
|
||||
}
|
||||
|
||||
- (santa_action_t)checkCache:(uint64_t)vnodeID {
|
||||
uint32_t input_count = 1;
|
||||
uint64_t vnode_action = 0;
|
||||
|
||||
IOConnectCallScalarMethod(_connection,
|
||||
kSantaUserClientCheckCache,
|
||||
&vnodeID,
|
||||
1,
|
||||
&vnode_action,
|
||||
&input_count);
|
||||
return (santa_action_t)vnode_action;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
|
||||
@interface SNTEventLog ()
|
||||
@property NSMutableDictionary *detailStore;
|
||||
@property dispatch_queue_t detailStoreQueue;
|
||||
@end
|
||||
|
||||
@implementation SNTEventLog
|
||||
@@ -36,18 +37,22 @@
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_detailStore = [NSMutableDictionary dictionaryWithCapacity:10000];
|
||||
_detailStoreQueue = dispatch_queue_create("com.google.santad.detail_store",
|
||||
DISPATCH_QUEUE_SERIAL);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)saveDecisionDetails:(SNTCachedDecision *)cd {
|
||||
self.detailStore[@(cd.vnodeId)] = cd;
|
||||
dispatch_sync(_detailStoreQueue, ^{
|
||||
_detailStore[@(cd.vnodeId)] = cd;
|
||||
});
|
||||
}
|
||||
|
||||
- (void)logFileModification:(santa_message_t)message {
|
||||
NSString *action, *path, *newpath, *sha256, *outStr;
|
||||
NSString *action, *newpath;
|
||||
|
||||
path = @(message.path);
|
||||
NSString *path = @(message.path);
|
||||
|
||||
switch (message.action) {
|
||||
case ACTION_NOTIFY_DELETE: {
|
||||
@@ -71,38 +76,30 @@
|
||||
}
|
||||
case ACTION_NOTIFY_WRITE: {
|
||||
action = @"WRITE";
|
||||
SNTFileInfo *fileInfo = [[SNTFileInfo alloc] initWithPath:path];
|
||||
if (fileInfo.fileSize < 1024 * 1024) {
|
||||
sha256 = fileInfo.SHA256;
|
||||
} else {
|
||||
sha256 = @"(too large)";
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: action = @"UNKNOWN"; break;
|
||||
}
|
||||
|
||||
outStr = [NSString stringWithFormat:@"action=%@|path=%@", action, [self sanitizeString:path]];
|
||||
// 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 = [outStr stringByAppendingFormat:@"|newpath=%@", [self sanitizeString:newpath]];
|
||||
[outStr appendFormat:@"|newpath=%@", [self sanitizeString:newpath]];
|
||||
}
|
||||
char ppath[PATH_MAX] = "(null)";
|
||||
proc_pidpath(message.pid, ppath, PATH_MAX);
|
||||
|
||||
NSString *user, *group;
|
||||
const char *user = "";
|
||||
const char *group = "";
|
||||
struct passwd *pw = getpwuid(message.uid);
|
||||
if (pw) user = @(pw->pw_name);
|
||||
if (pw) user = pw->pw_name;
|
||||
struct group *gr = getgrgid(message.gid);
|
||||
if (gr) group = @(gr->gr_name);
|
||||
|
||||
outStr = [outStr stringByAppendingFormat:(@"|pid=%d|ppid=%d|process=%s|processpath=%s|"
|
||||
@"uid=%d|user=%@|gid=%d|group=%@"),
|
||||
message.pid, message.ppid, message.pname, ppath,
|
||||
message.uid, user, message.gid, group];
|
||||
if (sha256) {
|
||||
outStr = [outStr stringByAppendingFormat:@"|sha256=%@", sha256];
|
||||
}
|
||||
if (gr) group = gr->gr_name;
|
||||
|
||||
[outStr appendFormat:@"|pid=%d|ppid=%d|process=%s|processpath=%s|uid=%d|user=%s|gid=%d|group=%s",
|
||||
message.pid, message.ppid, message.pname, ppath,
|
||||
message.uid, user, message.gid, group];
|
||||
LOGI(@"%@", outStr);
|
||||
}
|
||||
|
||||
@@ -111,33 +108,37 @@
|
||||
}
|
||||
|
||||
- (void)logAllowedExecution:(santa_message_t)message {
|
||||
SNTCachedDecision *cd = self.detailStore[@(message.vnode_id)];
|
||||
__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, *args, *outLog;
|
||||
NSString *d, *r;
|
||||
BOOL logArgs = NO;
|
||||
|
||||
switch (cd.decision) {
|
||||
case SNTEventStateAllowBinary:
|
||||
d = @"ALLOW";
|
||||
r = @"BINARY";
|
||||
args = [self argsForPid:message.pid];
|
||||
logArgs = YES;
|
||||
break;
|
||||
case SNTEventStateAllowCertificate:
|
||||
d = @"ALLOW";
|
||||
r = @"CERTIFICATE";
|
||||
args = [self argsForPid:message.pid];
|
||||
logArgs = YES;
|
||||
break;
|
||||
case SNTEventStateAllowScope:
|
||||
d = @"ALLOW";
|
||||
r = @"SCOPE";
|
||||
args = [self argsForPid:message.pid];
|
||||
logArgs = YES;
|
||||
break;
|
||||
case SNTEventStateAllowUnknown:
|
||||
d = @"ALLOW";
|
||||
r = @"UNKNOWN";
|
||||
args = [self argsForPid:message.pid];
|
||||
logArgs = YES;
|
||||
break;
|
||||
case SNTEventStateBlockBinary:
|
||||
d = @"DENY";
|
||||
@@ -158,28 +159,31 @@
|
||||
default:
|
||||
d = @"ALLOW";
|
||||
r = @"NOTRUNNING";
|
||||
args = [self argsForPid:message.pid];
|
||||
logArgs = YES;
|
||||
break;
|
||||
}
|
||||
|
||||
outLog = [NSString stringWithFormat:@"action=EXEC|decision=%@|reason=%@", d, r];
|
||||
// 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 = [outLog stringByAppendingFormat:@"|explain=%@", cd.decisionExtra];
|
||||
[outLog appendFormat:@"|explain=%@", cd.decisionExtra];
|
||||
}
|
||||
|
||||
outLog = [outLog stringByAppendingFormat:@"|sha256=%@|path=%@|args=%@", cd.sha256,
|
||||
[self sanitizeString:@(message.path)],
|
||||
[self sanitizeString:args]];
|
||||
[outLog appendFormat:@"|sha256=%@|path=%@", cd.sha256, [self sanitizeString:@(message.path)]];
|
||||
|
||||
if (logArgs) {
|
||||
[self addArgsForPid:message.pid toString:outLog];
|
||||
}
|
||||
|
||||
if (cd.certSHA256) {
|
||||
outLog = [outLog stringByAppendingFormat:@"|cert_sha256=%@|cert_cn=%@", cd.certSHA256,
|
||||
[self sanitizeString:cd.certCommonName]];
|
||||
[outLog appendFormat:@"|cert_sha256=%@|cert_cn=%@", cd.certSHA256,
|
||||
[self sanitizeString:cd.certCommonName]];
|
||||
}
|
||||
|
||||
if (cd.quarantineURL) {
|
||||
outLog = [outLog stringByAppendingFormat:@"|quarantine_url=%@",
|
||||
[self sanitizeString:cd.quarantineURL]];
|
||||
[outLog appendFormat:@"|quarantine_url=%@", [self sanitizeString:cd.quarantineURL]];
|
||||
}
|
||||
|
||||
NSString *user, *group;
|
||||
@@ -188,9 +192,9 @@
|
||||
struct group *gr = getgrgid(message.gid);
|
||||
if (gr) group = @(gr->gr_name);
|
||||
|
||||
outLog = [outLog stringByAppendingFormat:@"|pid=%d|ppid=%d|uid=%d|user=%@|gid=%d|group=%@",
|
||||
message.pid, message.ppid, message.uid, user,
|
||||
message.gid, group];
|
||||
[outLog appendFormat:@"|pid=%d|ppid=%d|uid=%d|user=%@|gid=%d|group=%@",
|
||||
message.pid, message.ppid, message.uid, user,
|
||||
message.gid, group];
|
||||
|
||||
LOGI(@"%@", outLog);
|
||||
}
|
||||
@@ -234,70 +238,162 @@
|
||||
|
||||
#pragma mark Helpers
|
||||
|
||||
/**
|
||||
Sanitizes a given string if necessary, otherwise returns the original.
|
||||
*/
|
||||
- (NSString *)sanitizeString:(NSString *)inStr {
|
||||
inStr = [inStr stringByReplacingOccurrencesOfString:@"|" withString:@"<pipe>"];
|
||||
inStr = [inStr stringByReplacingOccurrencesOfString:@"\n" withString:@"\\n"];
|
||||
inStr = [inStr stringByReplacingOccurrencesOfString:@"\r" withString:@"\\r"];
|
||||
NSUInteger length = [inStr lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
|
||||
if (length < 1) return inStr;
|
||||
|
||||
NSString *ret = [self sanitizeCString:inStr.UTF8String ofLength:length];
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
return inStr;
|
||||
}
|
||||
|
||||
/**
|
||||
Use sysctl to get the arguments for a PID, returned as a single string.
|
||||
Sanitize the given C-string, replacing |, \n and \r characters.
|
||||
|
||||
@return a new NSString with the replaced contents, if necessary, otherwise nil.
|
||||
*/
|
||||
- (NSString *)argsForPid:(pid_t)pid {
|
||||
int mib[3];
|
||||
- (NSString *)sanitizeCString:(const char *)str ofLength:(NSUInteger)length {
|
||||
NSUInteger bufOffset = 0, strOffset = 0;
|
||||
char c = 0;
|
||||
char *buf = NULL;
|
||||
BOOL shouldFree = NO;
|
||||
|
||||
// Get size of buffer required to store process arguments.
|
||||
mib[0] = CTL_KERN;
|
||||
mib[1] = KERN_ARGMAX;
|
||||
int argmax;
|
||||
size_t size = sizeof(argmax);
|
||||
// Loop through the string one character at a time, looking for the characters
|
||||
// we want to remove.
|
||||
for (const char *p = str; (c = *p) != 0; ++p) {
|
||||
if (c == '|' || c == '\n' || c == '\r') {
|
||||
if (!buf) {
|
||||
// If string size * 6 is more than 64KiB use malloc, otherwise use stack space.
|
||||
if (length * 6 > 64 * 1024) {
|
||||
buf = malloc(length * 6);
|
||||
shouldFree = YES;
|
||||
} else {
|
||||
buf = alloca(length * 6);
|
||||
}
|
||||
}
|
||||
|
||||
if (sysctl(mib, 2, &argmax, &size, NULL, 0) == -1) return nil;
|
||||
// Copy from the last offset up to the character we just found into the buffer
|
||||
ptrdiff_t diff = p - str;
|
||||
memcpy(buf + bufOffset, str + strOffset, diff - strOffset);
|
||||
|
||||
// Create buffer to store args
|
||||
NSMutableData *argsdata = [NSMutableData dataWithCapacity:argmax];
|
||||
char *argsdatabytes = (char *)argsdata.mutableBytes;
|
||||
// Update the buffer and string offsets
|
||||
bufOffset += diff - strOffset;
|
||||
strOffset = diff + 1;
|
||||
|
||||
// Fetch args
|
||||
mib[0] = CTL_KERN;
|
||||
mib[1] = KERN_PROCARGS2;
|
||||
mib[2] = pid;
|
||||
size = (size_t)argmax;
|
||||
if (sysctl(mib, 3, argsdatabytes, &size, NULL, 0) == -1) return nil;
|
||||
|
||||
// Get argc
|
||||
int argc;
|
||||
memcpy(&argc, argsdatabytes, sizeof(argc));
|
||||
|
||||
// Get pointer to beginning of string space
|
||||
char *cp = (char *)argsdatabytes + sizeof(argc);
|
||||
|
||||
// Skip over exec_path
|
||||
for (; cp < &argsdatabytes[size]; ++cp) {
|
||||
if (*cp == '\0') {
|
||||
cp++;
|
||||
break;
|
||||
// Replace the found character and advance the buffer offset
|
||||
switch (c) {
|
||||
case '|':
|
||||
memcpy(buf + bufOffset, "<pipe>", 6);
|
||||
bufOffset += 6;
|
||||
break;
|
||||
case '\n':
|
||||
memcpy(buf + bufOffset, "\\n", 2);
|
||||
bufOffset += 2;
|
||||
break;
|
||||
case '\r':
|
||||
memcpy(buf + bufOffset, "\\r", 2);
|
||||
bufOffset += 2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Skip trailing NULL bytes
|
||||
for (; cp < &argsdatabytes[size]; ++cp) {
|
||||
if (*cp != '\0') break;
|
||||
if (strOffset > 0 && strOffset < length) {
|
||||
// Copy any characters from the last match to the end of the string into the buffer.
|
||||
memcpy(buf + bufOffset, str + strOffset, length - strOffset);
|
||||
bufOffset += length - strOffset;
|
||||
}
|
||||
|
||||
// Loop over the argv array, stripping newlines in each arg and putting in a new array.
|
||||
NSMutableArray *args = [NSMutableArray arrayWithCapacity:argc];
|
||||
for (int i = 0; i < argc; ++i) {
|
||||
NSString *arg = @(cp);
|
||||
if (arg) [args addObject:arg];
|
||||
if (buf) {
|
||||
// Only return a new string if there were matches
|
||||
NSString *ret = [[NSString alloc] initWithBytes:buf
|
||||
length:bufOffset
|
||||
encoding:NSUTF8StringEncoding];
|
||||
if (shouldFree) {
|
||||
free(buf);
|
||||
}
|
||||
|
||||
// Move the pointer past this string and the terminator at the end.
|
||||
cp += strlen(cp) + 1;
|
||||
return ret;
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
/**
|
||||
Use sysctl to get the arguments for a PID, appended to the given string.
|
||||
*/
|
||||
- (void)addArgsForPid:(pid_t)pid toString:(NSMutableString *)str {
|
||||
size_t argsSizeEstimate = 0, argsSize = 0, index = 0;
|
||||
|
||||
// Use stack space up to 128KiB.
|
||||
const size_t MAX_STACK_ALLOC = 128 * 1024;
|
||||
char *bytes = alloca(MAX_STACK_ALLOC);
|
||||
BOOL shouldFree = NO;
|
||||
|
||||
int mib[] = {CTL_KERN, KERN_PROCARGS2, pid};
|
||||
|
||||
// Get estimated length of arg array
|
||||
if (sysctl(mib, 3, NULL, &argsSizeEstimate, NULL, 0) < 0) return;
|
||||
argsSize = argsSizeEstimate + 512;
|
||||
|
||||
// If this is larger than our allocated stack space, alloc from heap.
|
||||
if (argsSize > MAX_STACK_ALLOC) {
|
||||
bytes = malloc(argsSize);
|
||||
shouldFree = YES;
|
||||
}
|
||||
|
||||
// Return the args as a space-separated list
|
||||
return [args componentsJoinedByString:@" "];
|
||||
// Get the args. If this fails, free if necessary and return.
|
||||
if (sysctl(mib, 3, bytes, &argsSize, NULL, 0) != 0 || argsSize >= argsSizeEstimate + 512) {
|
||||
if (shouldFree) {
|
||||
free(bytes);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Get argc, set index to the end of argc
|
||||
int argc = 0;
|
||||
memcpy(&argc, &bytes[0], sizeof(argc));
|
||||
index = sizeof(argc);
|
||||
|
||||
// Skip past end of executable path and trailing NULLs
|
||||
for (; index < argsSize; ++index) {
|
||||
if (bytes[index] == '\0') {
|
||||
++index;
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (; index < argsSize; ++index) {
|
||||
if (bytes[index] != '\0') break;
|
||||
}
|
||||
|
||||
// Save the beginning of the arguments
|
||||
size_t stringStart = index;
|
||||
|
||||
// Replace all NULLs with spaces up until the first environment variable
|
||||
int replacedNulls = 0;
|
||||
for (; index < argsSize; ++index) {
|
||||
if (bytes[index] == '\0') {
|
||||
++replacedNulls;
|
||||
if (replacedNulls == argc) break;
|
||||
bytes[index] = ' ';
|
||||
}
|
||||
}
|
||||
|
||||
// Potentially sanitize the args string.
|
||||
NSString *sanitized = [self sanitizeCString:&bytes[stringStart] ofLength:index - stringStart];
|
||||
if (sanitized) {
|
||||
[str appendFormat:@"|args=%@", sanitized];
|
||||
} else {
|
||||
[str appendFormat:@"|args=%s", &bytes[stringStart]];
|
||||
}
|
||||
|
||||
if (shouldFree) {
|
||||
free(bytes);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -309,8 +405,7 @@
|
||||
- (NSString *)diskImageForDevice:(NSString *)devPath {
|
||||
devPath = [devPath stringByDeletingLastPathComponent];
|
||||
if (!devPath.length) return nil;
|
||||
io_registry_entry_t device = IORegistryEntryCopyFromPath(
|
||||
kIOMasterPortDefault, (__bridge CFStringRef)devPath);
|
||||
io_registry_entry_t device = IORegistryEntryFromPath(kIOMasterPortDefault, devPath.UTF8String);
|
||||
CFMutableDictionaryRef deviceProperties = NULL;
|
||||
IORegistryEntryCreateCFProperties(device, &deviceProperties, kCFAllocatorDefault, kNilOptions);
|
||||
NSDictionary *properties = CFBridgingRelease(deviceProperties);
|
||||
@@ -329,8 +424,7 @@
|
||||
- (NSString *)serialForDevice:(NSString *)devPath {
|
||||
if (!devPath.length) return nil;
|
||||
NSString *serial;
|
||||
io_registry_entry_t device = IORegistryEntryCopyFromPath(
|
||||
kIOMasterPortDefault, (__bridge CFStringRef)devPath);
|
||||
io_registry_entry_t device = IORegistryEntryFromPath(kIOMasterPortDefault, devPath.UTF8String);
|
||||
while (!serial && device) {
|
||||
CFMutableDictionaryRef deviceProperties = NULL;
|
||||
IORegistryEntryCreateCFProperties(device, &deviceProperties, kCFAllocatorDefault, kNilOptions);
|
||||
|
||||
@@ -34,12 +34,6 @@
|
||||
///
|
||||
@interface SNTExecutionController : NSObject
|
||||
|
||||
@property SNTDriverManager *driverManager;
|
||||
@property SNTEventLog *eventLog;
|
||||
@property SNTEventTable *eventTable;
|
||||
@property SNTNotificationQueue *notifierQueue;
|
||||
@property SNTRuleTable *ruleTable;
|
||||
|
||||
- (instancetype)initWithDriverManager:(SNTDriverManager *)driverManager
|
||||
ruleTable:(SNTRuleTable *)ruleTable
|
||||
eventTable:(SNTEventTable *)eventTable
|
||||
|
||||
@@ -36,6 +36,17 @@
|
||||
#import "SNTRuleTable.h"
|
||||
#import "SNTStoredEvent.h"
|
||||
|
||||
@interface SNTExecutionController ()
|
||||
@property SNTDriverManager *driverManager;
|
||||
@property SNTEventLog *eventLog;
|
||||
@property SNTEventTable *eventTable;
|
||||
@property SNTNotificationQueue *notifierQueue;
|
||||
@property SNTRuleTable *ruleTable;
|
||||
|
||||
@property NSMutableDictionary *uploadBackoff;
|
||||
@property dispatch_queue_t eventQueue;
|
||||
@end
|
||||
|
||||
@implementation SNTExecutionController
|
||||
|
||||
#pragma mark Initializers
|
||||
@@ -53,6 +64,9 @@
|
||||
_notifierQueue = notifierQueue;
|
||||
_eventLog = eventLog;
|
||||
|
||||
_uploadBackoff = [NSMutableDictionary dictionaryWithCapacity:128];
|
||||
_eventQueue = dispatch_queue_create("com.google.santad.event_upload", DISPATCH_QUEUE_SERIAL);
|
||||
|
||||
// This establishes the XPC connection between libsecurity and syspolicyd.
|
||||
// Not doing this causes a deadlock as establishing this link goes through xpcproxy.
|
||||
(void)[[MOLCodesignChecker alloc] initWithSelf];
|
||||
@@ -63,7 +77,7 @@
|
||||
#pragma mark Binary Validation
|
||||
|
||||
- (SNTEventState)makeDecision:(SNTCachedDecision *)cd binaryInfo:(SNTFileInfo *)fi {
|
||||
SNTRule *rule = [self.ruleTable binaryRuleForSHA256:cd.sha256];
|
||||
SNTRule *rule = [_ruleTable binaryRuleForSHA256:cd.sha256];
|
||||
if (rule) {
|
||||
switch (rule.state) {
|
||||
case SNTRuleStateWhitelist:
|
||||
@@ -77,7 +91,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
rule = [self.ruleTable certificateRuleForSHA256:cd.certSHA256];
|
||||
rule = [_ruleTable certificateRuleForSHA256:cd.certSHA256];
|
||||
if (rule) {
|
||||
switch (rule.state) {
|
||||
case SNTRuleStateWhitelist:
|
||||
@@ -116,8 +130,7 @@
|
||||
SNTFileInfo *binInfo = [[SNTFileInfo alloc] initWithPath:@(message.path) error:&fileInfoError];
|
||||
if (!binInfo) {
|
||||
LOGW(@"Failed to read file %@: %@", binInfo.path, fileInfoError.localizedDescription);
|
||||
[self.driverManager postToKernelAction:ACTION_RESPOND_ALLOW
|
||||
forVnodeID:message.vnode_id];
|
||||
[_driverManager postToKernelAction:ACTION_RESPOND_ALLOW forVnodeID:message.vnode_id];
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -138,10 +151,10 @@
|
||||
|
||||
// Save decision details for logging the execution later.
|
||||
santa_action_t action = [self actionForEventState:cd.decision];
|
||||
if (action == ACTION_RESPOND_ALLOW) [self.eventLog saveDecisionDetails:cd];
|
||||
if (action == ACTION_RESPOND_ALLOW) [_eventLog saveDecisionDetails:cd];
|
||||
|
||||
// Send the decision to the kernel.
|
||||
[self.driverManager postToKernelAction:action forVnodeID:cd.vnodeId];
|
||||
[_driverManager postToKernelAction:action forVnodeID:cd.vnodeId];
|
||||
|
||||
// Log to database if necessary.
|
||||
if (cd.decision != SNTEventStateAllowBinary &&
|
||||
@@ -183,28 +196,36 @@
|
||||
se.quarantineTimestamp = binInfo.quarantineTimestamp;
|
||||
se.quarantineAgentBundleID = binInfo.quarantineAgentBundleID;
|
||||
|
||||
[self.eventTable addStoredEvent:se];
|
||||
dispatch_async(_eventQueue, ^{
|
||||
[_eventTable addStoredEvent:se];
|
||||
});
|
||||
|
||||
// If binary was blocked, do the needful
|
||||
if (action != ACTION_RESPOND_ALLOW) {
|
||||
[self.eventLog logDeniedExecution:cd withMessage:message];
|
||||
[_eventLog logDeniedExecution:cd withMessage:message];
|
||||
|
||||
// So the server has something to show the user straight away, initiate an event
|
||||
// upload for the blocked binary rather than waiting for the next sync.
|
||||
[self initiateEventUploadForEvent:se];
|
||||
dispatch_async(_eventQueue, ^{
|
||||
[self initiateEventUploadForEvent:se];
|
||||
});
|
||||
|
||||
if (!cd.silentBlock) {
|
||||
// Let the user know what happened, both on the terminal and in the GUI.
|
||||
NSAttributedString *s = [SNTBlockMessage attributedBlockMessageForEvent:se
|
||||
customMessage:cd.customMsg];
|
||||
NSString *msg = [NSString stringWithFormat:@"\033[1mSanta\033[0m\n\n%@\n\n", s.string];
|
||||
msg = [msg stringByAppendingFormat:@"\033[1mPath:\033[0m %@\n"
|
||||
@"\033[1mIdentifier:\033[0m %@\n"
|
||||
@"\033[1mParent:\033[0m %@ (%@)\n\n",
|
||||
se.filePath, se.fileSHA256, se.parentName, se.ppid];
|
||||
NSURL *detailURL = [SNTBlockMessage eventDetailURLForEvent:se];
|
||||
if (detailURL) {
|
||||
msg = [msg stringByAppendingFormat:@"%@\n\n", detailURL.absoluteString];
|
||||
}
|
||||
[self printMessage:msg toTTYForPID:message.ppid];
|
||||
|
||||
[self.notifierQueue addEvent:se customMessage:cd.customMsg];
|
||||
[_notifierQueue addEvent:se customMessage:cd.customMsg];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -251,18 +272,18 @@
|
||||
|
||||
/**
|
||||
Workaround for issue with PrinterProxy.app.
|
||||
|
||||
|
||||
Every time a new printer is added to the machine, a copy of the PrinterProxy.app is copied from
|
||||
the Print.framework to ~/Library/Printers with the name of the printer as the name of the app.
|
||||
The binary inside is changed slightly (in a way that is unique to the printer name) and then
|
||||
re-signed with an adhoc signature. I don't know why this is done but it seems that the binary
|
||||
The binary inside is changed slightly (in a way that is unique to the printer name) and then
|
||||
re-signed with an adhoc signature. I don't know why this is done but it seems that the binary
|
||||
itself doesn't need to be changed as copying the old one back in-place seems to work,
|
||||
so that's what we do.
|
||||
|
||||
|
||||
If this workaround is applied the decision request is not responded to as the existing request
|
||||
is invalidated when the file is closed which will trigger a brand new request coming from the
|
||||
kernel.
|
||||
|
||||
|
||||
@param fi, SNTFileInfo object for the binary being executed.
|
||||
@return YES if the workaround was applied, NO otherwise.
|
||||
*/
|
||||
@@ -300,15 +321,12 @@
|
||||
|
||||
// The event upload is skipped if an event upload has been initiated for it in the
|
||||
// last 10 minutes.
|
||||
static dispatch_once_t onceToken;
|
||||
static NSMutableDictionary *uploadBackoff;
|
||||
dispatch_once(&onceToken, ^{
|
||||
uploadBackoff = [NSMutableDictionary dictionary];
|
||||
});
|
||||
NSDate *backoff = uploadBackoff[event.fileSHA256];
|
||||
NSDate *backoff = self.uploadBackoff[event.fileSHA256];
|
||||
|
||||
NSDate *now = [NSDate date];
|
||||
if (([now timeIntervalSince1970] - [backoff timeIntervalSince1970]) < 600) return;
|
||||
uploadBackoff[event.fileSHA256] = now;
|
||||
|
||||
self.uploadBackoff[event.fileSHA256] = now;
|
||||
|
||||
if (fork() == 0) {
|
||||
// Ensure we have no privileges
|
||||
|
||||
@@ -35,7 +35,7 @@ void *watchdogThreadFunction(__unused void *idata) {
|
||||
pthread_setname_np("com.google.santa.watchdog");
|
||||
|
||||
// Number of seconds to wait between checks.
|
||||
const int timeInterval = 60;
|
||||
const int timeInterval = 30;
|
||||
|
||||
// Amount of CPU usage to trigger warning, as a percentage averaged over timeInterval
|
||||
// santad's usual CPU usage is 0-3% but can occasionally spike if lots of processes start at once.
|
||||
|
||||
@@ -16,9 +16,14 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <IOKit/IODataQueueClient.h>
|
||||
|
||||
#include <cmath>
|
||||
#include <ctime>
|
||||
#include <iostream>
|
||||
#include <mach/mach.h>
|
||||
#include <numeric>
|
||||
#include <sys/ptrace.h>
|
||||
#include <sys/types.h>
|
||||
#include <vector>
|
||||
|
||||
#include "SNTKernelCommon.h"
|
||||
|
||||
@@ -152,6 +157,13 @@
|
||||
TFAILINFO("KR: %d", kr);
|
||||
}
|
||||
TPASS();
|
||||
|
||||
TSTART("Refuses second client");
|
||||
kr = IOConnectCallMethod(self.connection, kSantaUserClientOpen, 0, 0, 0, 0, 0, 0, 0, 0);
|
||||
if (kr != kIOReturnExclusiveAccess) {
|
||||
TFAIL();
|
||||
}
|
||||
TPASS();
|
||||
}
|
||||
|
||||
#pragma mark - Listener
|
||||
@@ -312,7 +324,7 @@
|
||||
|
||||
/// Tests that a write to a cached vnode will invalidate the cached response for that file
|
||||
- (void)invalidatesCacheTests {
|
||||
TSTART("Invalidates cache correctly");
|
||||
TSTART("Invalidates cache for manually closed FDs");
|
||||
|
||||
// Copy the ls binary to a new file
|
||||
NSFileManager *fm = [NSFileManager defaultManager];
|
||||
@@ -369,6 +381,49 @@
|
||||
}
|
||||
}
|
||||
|
||||
- (void)invalidatesCacheAutoCloseTest {
|
||||
TSTART("Invalidates cache for auto-closed FDs");
|
||||
|
||||
// Check invalidations when kernel auto-closes descriptors
|
||||
NSFileManager *fm = [NSFileManager defaultManager];
|
||||
if (![fm copyItemAtPath:@"/bin/pwd" toPath:@"invalidacachetest_tmp" error:nil]) {
|
||||
TFAILINFO("Failed to create temp file");
|
||||
}
|
||||
|
||||
// Launch the new file to put it in the cache
|
||||
NSTask *pwd = [self taskWithPath:@"invalidacachetest_tmp"];
|
||||
[pwd launch];
|
||||
[pwd waitUntilExit];
|
||||
|
||||
// Exit if this fails with a useful message.
|
||||
if ([pwd terminationStatus] != 0) {
|
||||
TFAILINFO("Second launch of test binary failed");
|
||||
}
|
||||
|
||||
// Replace file contents
|
||||
NSDictionary *attrs = [fm attributesOfItemAtPath:@"/bin/ed" error:NULL];
|
||||
NSTask *dd = [self taskWithPath:@"/bin/dd"];
|
||||
dd.arguments = @[ @"if=/bin/ed",
|
||||
@"of=invalidacachetest_tmp",
|
||||
@"bs=1",
|
||||
[NSString stringWithFormat:@"count=%@", attrs[NSFileSize]]
|
||||
];
|
||||
[dd launch];
|
||||
[dd waitUntilExit];
|
||||
|
||||
// And try running the temp file again. If it succeeds, the test failed.
|
||||
NSTask *ed = [self taskWithPath:@"invalidacachetest_tmp"];
|
||||
@try {
|
||||
[ed launch];
|
||||
[ed waitUntilExit];
|
||||
TFAILINFO("Launched after file closed");
|
||||
} @catch (NSException *exception) {
|
||||
TPASS();
|
||||
} @finally {
|
||||
[fm removeItemAtPath:@"invalidacachetest_tmp" error:nil];
|
||||
}
|
||||
}
|
||||
|
||||
/// Tests the clear cache function works correctly
|
||||
- (void)clearCacheTests {
|
||||
TSTART("Can clear cache");
|
||||
@@ -452,6 +507,48 @@
|
||||
TPASS();
|
||||
}
|
||||
|
||||
- (void)testCachePerformance {
|
||||
TSTART("Test cache performance");
|
||||
|
||||
// Execute echo 100 times, saving the time taken for each run
|
||||
std::vector<std::clock_t> times;
|
||||
for (int i = 0; i < 100; ++i) {
|
||||
printf("\033[s"); // save cursor position
|
||||
printf("%d/%d", i + 1, 100);
|
||||
auto start = std::clock();
|
||||
NSTask *t = [[NSTask alloc] init];
|
||||
t.launchPath = @"/bin/echo";
|
||||
t.standardOutput = [NSPipe pipe];
|
||||
[t launch];
|
||||
[t waitUntilExit];
|
||||
if (i > 5) times.push_back(std::clock() - start);
|
||||
printf("\033[u"); // restore cursor position
|
||||
}
|
||||
|
||||
printf("\033[K\033[u"); // clear line, restore cursor position
|
||||
|
||||
// Sort and remove first 10 and last 10 entries.
|
||||
std::sort(times.begin(), times.end());
|
||||
times.erase(times.begin(), times.begin()+10);
|
||||
times.erase(times.end()-10, times.end());
|
||||
|
||||
// Calculate mean
|
||||
double mean = std::accumulate(times.begin(), times.end(), 0.0) / times.size();
|
||||
|
||||
// Calculate stdev
|
||||
double accum = 0.0;
|
||||
std::for_each(times.begin(), times.end(), [&](const double d) {
|
||||
accum += (d - mean) * (d - mean);
|
||||
});
|
||||
double stdev = sqrt(accum / (times.size()-1));
|
||||
|
||||
if (mean > 1000 || stdev > 150) {
|
||||
TFAILINFO("μ: %-3.2f σ: %-3.2f", mean, stdev);
|
||||
} else {
|
||||
TPASSINFO("μ: %-3.2f σ: %-3.2f", mean, stdev);
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Main
|
||||
|
||||
- (void)runTests {
|
||||
@@ -472,8 +569,12 @@
|
||||
[self receiveAndBlockTests];
|
||||
[self receiveAndCacheTests];
|
||||
[self invalidatesCacheTests];
|
||||
[self invalidatesCacheAutoCloseTest];
|
||||
[self clearCacheTests];
|
||||
[self blocksDeniedTracedBinaries];
|
||||
|
||||
printf("\n-> Performance tests:\033[m\n");
|
||||
[self testCachePerformance];
|
||||
[self handlesLotsOfBinaries];
|
||||
|
||||
printf("\nAll tests passed.\n\n");
|
||||
@@ -338,7 +338,7 @@
|
||||
NSArray *events = [NSKeyedUnarchiver unarchiveObjectWithData:eventData];
|
||||
OCMStub([self.daemonConnRop databaseEventsPending:([OCMArg invokeBlockWithArgs:events, nil])]);
|
||||
|
||||
__block int requestCount;
|
||||
__block int requestCount = 0;
|
||||
|
||||
[self stubRequestBody:nil response:nil error:nil validateBlock:^BOOL(NSURLRequest *req) {
|
||||
requestCount++;
|
||||
|
||||
153
Tests/LogicTests/SantaCacheTest.mm
Normal file
153
Tests/LogicTests/SantaCacheTest.mm
Normal file
@@ -0,0 +1,153 @@
|
||||
/// Copyright 2016 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 <XCTest/XCTest.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "SantaCache.h"
|
||||
|
||||
@interface SantaCacheTest : XCTestCase
|
||||
@end
|
||||
|
||||
@implementation SantaCacheTest
|
||||
|
||||
- (void)setUp {
|
||||
self.continueAfterFailure = NO;
|
||||
}
|
||||
|
||||
- (void)testSetAndGet {
|
||||
auto sut = new SantaCache<uint64_t>();
|
||||
|
||||
sut->set(72057611258548992llu, 10000192);
|
||||
XCTAssertEqual(sut->get(72057611258548992llu), 10000192);
|
||||
|
||||
delete sut;
|
||||
}
|
||||
|
||||
- (void)testCacheRemove {
|
||||
auto sut = new SantaCache<uint64_t>();
|
||||
|
||||
sut->set(0xDEADBEEF, 42);
|
||||
sut->remove(0xDEADBEEF);
|
||||
|
||||
XCTAssertEqual(sut->get(0xDEADBEEF), 0);
|
||||
|
||||
delete sut;
|
||||
}
|
||||
|
||||
- (void)testBucketGrowCopy {
|
||||
auto sut = new SantaCache<uint64_t>();
|
||||
|
||||
sut->set(386, 42);
|
||||
sut->set(2434, 42);
|
||||
|
||||
XCTAssertEqual(sut->get(386), 42);
|
||||
XCTAssertEqual(sut->get(2434), 42);
|
||||
|
||||
delete sut;
|
||||
}
|
||||
|
||||
- (void)testBucketShrinkCopy {
|
||||
auto sut = new SantaCache<uint64_t>(100, 1);
|
||||
|
||||
sut->set(386, 42);
|
||||
sut->set(2434, 42);
|
||||
sut->set(4482, 42);
|
||||
|
||||
sut->remove(2434);
|
||||
|
||||
XCTAssertEqual(sut->get(386), 42);
|
||||
XCTAssertEqual(sut->get(2434), 0);
|
||||
XCTAssertEqual(sut->get(4482), 42);
|
||||
|
||||
delete sut;
|
||||
}
|
||||
|
||||
- (void)testCacheResetAtLimit {
|
||||
auto sut = new SantaCache<uint64_t>(5);
|
||||
|
||||
sut->set(1, 42);
|
||||
sut->set(2, 42);
|
||||
sut->set(3, 42);
|
||||
sut->set(4, 42);
|
||||
sut->set(5, 42);
|
||||
XCTAssertEqual(sut->get(3), 42);
|
||||
sut->set(6, 42);
|
||||
XCTAssertEqual(sut->get(3), 0);
|
||||
XCTAssertEqual(sut->get(6), 42);
|
||||
|
||||
delete sut;
|
||||
}
|
||||
|
||||
- (void)testThreading {
|
||||
auto sut = new SantaCache<uint64_t>();
|
||||
|
||||
for (int x = 0; x < 200; ++x) {
|
||||
dispatch_group_t group = dispatch_group_create();
|
||||
|
||||
dispatch_group_enter(group);
|
||||
dispatch_async(dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0), ^{
|
||||
for (int i = 0; i < 5000; ++i) sut->set(i, 10000-i);
|
||||
dispatch_group_leave(group);
|
||||
});
|
||||
|
||||
dispatch_group_enter(group);
|
||||
dispatch_async(dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0), ^{
|
||||
for (int i = 5000; i < 10000; ++i) sut->set(i, 10000-i);
|
||||
dispatch_group_leave(group);
|
||||
});
|
||||
|
||||
if (dispatch_group_wait(group, dispatch_time(DISPATCH_TIME_NOW, 5 * NSEC_PER_SEC))) {
|
||||
XCTFail("Timed out while setting values for test");
|
||||
}
|
||||
|
||||
for (int i = 0; i < 10000; ++i) XCTAssertEqual(sut->get(i), 10000 - i);
|
||||
}
|
||||
|
||||
delete sut;
|
||||
}
|
||||
|
||||
- (void)testCount {
|
||||
auto sut = new SantaCache<uint64_t>();
|
||||
|
||||
XCTAssertEqual(sut->count(), 0);
|
||||
|
||||
sut->set(4012, 42);
|
||||
sut->set(42, 0);
|
||||
sut->set(0x8BADF00D, 40010);
|
||||
|
||||
XCTAssertEqual(sut->count(), 2);
|
||||
|
||||
delete sut;
|
||||
}
|
||||
|
||||
- (void)testStrings {
|
||||
auto sut = new SantaCache<std::string>();
|
||||
|
||||
sut->set(1, "deadbeef");
|
||||
sut->set(2, "feedface");
|
||||
|
||||
XCTAssertEqual(sut->count(), 2);
|
||||
XCTAssertEqual(sut->get(1), "deadbeef");
|
||||
XCTAssertEqual(sut->get(2), "feedface");
|
||||
|
||||
sut->remove(2);
|
||||
|
||||
XCTAssertTrue(sut->get(2).empty());
|
||||
|
||||
delete sut;
|
||||
}
|
||||
|
||||
@end
|
||||
Reference in New Issue
Block a user