Compare commits

..

63 Commits
1.7 ... 2021.1

Author SHA1 Message Date
Russell Hancox
a9e5bf09a7 santad: Add some TODOs related to cache 2021-01-11 13:16:38 -05:00
Russell Hancox
4ee3f281c3 santactl/status: Output cache details for sysx 2021-01-11 13:16:38 -05:00
Russell Hancox
462ce89d42 Project: Fix test locations 2021-01-11 13:16:38 -05:00
Russell Hancox
44117833c0 Project: Fix build rule 2021-01-11 13:16:38 -05:00
Russell Hancox
8b6e029da2 Project: bump version to 2021.1
This is a new versioning scheme.
2021-01-11 13:16:38 -05:00
Russell Hancox
f183e246df santad: Make use of caching endpoint security optional 2021-01-11 13:16:38 -05:00
Russell Hancox
c60a35f280 santad: Add caching layer to EndpointSecurity
This first commit is very rough, just adding the caching as simply as
possible. Refactoring is needed.
2021-01-11 13:16:38 -05:00
Russell Hancox
4f65965277 santactl/fileinfo: Fix fileinfo tests on BigSur + multiarch plists (#523)
The fileinfo tests didn't work on BigSur because of some path and binary changes.

Also, the embeddedPlist method didn't work on fat binaries, of which there are now
many, because of M1 machines. I think we didn't notice this before because we pull
the embedded plist from the first arch listed in the headers dict which generally
seemed to pick x86_64 first but with the arm64/arm64e option being added
that now appears first.

Also fixed some errors handling 32-bit segment/sections and added a test for this.
2021-01-07 19:46:48 -05:00
Tom Burgin
01e4e15b81 santactl sync: add config option to enable legacy zlib content encoding (#522) 2020-12-23 10:36:39 -05:00
Russell Hancox
532cb37e0b CI: split out driver and userspace builds (#521) 2020-12-23 08:38:39 -05:00
Tom Burgin
9d379d3884 release: split out the kext into a separate release label (#520)
* fix SNTLoggingKernel BUILD rule (#518)

* release: split out santa-driver.kext

* release: update ci

* remove ipa script rule

* update ci
2020-12-19 18:23:54 -05:00
Tom Burgin
3e7a191bf7 fix SNTLoggingKernel BUILD rule (#518) 2020-12-17 16:35:13 -05:00
Ryan Diers
c5a048f4d9 santactl/sync: Use deflate as Content-Encoding instead of zlib
The latter was not standards-compliant.
2020-12-14 16:19:48 -05:00
Hugh Neale
f4769bad90 Added Zercurity to list of available sync servers (#511) 2020-12-08 20:29:28 -05:00
Russell Hancox
254497ad15 Project: don't reference obsolete rake commands in CONTRIBUTING (#513) 2020-12-08 09:57:42 -05:00
avanzini
0a83445838 Log pidversion along with pid. (#512) 2020-12-08 09:46:34 -05:00
Tom Burgin
eff287259e project: update Xcode project to build universal binaries (#509) 2020-11-17 16:18:16 -05:00
Russell Hancox
6f2c0e3457 Project: remove Travis, update CI status in README (#508) 2020-11-02 09:59:35 -05:00
Russell Hancox
38769f7cd1 Project: Add GitHub Actions CI workflow (#507) 2020-10-30 12:23:01 -04:00
Russell Hancox
fa785ad3c2 Kernel: fix some header imports (#505) 2020-10-26 10:05:25 -04:00
Russell Hancox
5dae0cabdd Project: fix some lint (#504) 2020-10-22 14:01:32 -04:00
Russell Hancox
a8b4f4ea7e Project: move travis to xcode12 (#503) 2020-10-22 13:50:32 -04:00
Russell Hancox
2221c93bbc santa-driver: Fix some new Xcode 12 warnings (#502)
The ossharedptr-misuse warning is generated from within system headers and I couldn't
find a simple way to prevent that other than disabling the warning entirely. We don't
use OSSharedPtr directly anyway.
2020-10-22 13:41:31 -04:00
Tom Burgin
d1c33baf35 project: add EnableDebugLogging option (#501)
* project: add EnableDebugLogging option

* review updates
2020-10-22 10:11:18 -04:00
Tom Burgin
d2bbdff373 Add the option to ignore actions from other ES clients (#498)
* [com.google.santa.daemon]: add the option to ignore actions from other ES clients

* review updates

* review updates
2020-10-21 13:20:13 -04:00
Russell Hancox
db1d65f944 Project: Update dependency versions (#500)
MOLAuthenticatingURLSession: v2.8 -> v2.9
rules_apple: v0.19.0 -> v0.20.0
2020-10-21 11:55:38 -04:00
Hugh Neale
d17aeac2f4 Make it possible to remotely set the FullSyncInterval (#494)
Make it possible for the sync server to set the FullSyncInterval with "full_sync_interval" during `preflight`
2020-10-01 13:47:55 -04:00
Hugh Neale
7840270dd0 Support for %hostname%, %uuid% and %serial% to eventDetailURLForEvent (#493)
Added support for %hostname%, %uuid% and %serial% to eventDetailURLForEvent to provide additional system information for blocked events & updated documentation references for supported URL params.
2020-08-31 10:38:35 -04:00
Russell Hancox
dcf44c9872 Fix video in README (#492)
Fixes #491
2020-08-27 17:28:40 -04:00
Russell Hancox
fc365c888f Create CNAME 2020-08-27 16:21:08 -04:00
Russell Hancox
85f0782399 Delete CNAME 2020-08-27 16:21:03 -04:00
Russell Hancox
64bc34c302 santactl/rule: make flags consistent with help text (#486) 2020-07-29 13:39:41 -04:00
Russell Hancox
e2fc4c735d santad: Prevent kext from being loaded when ES is running (#484) 2020-07-21 10:18:22 -04:00
Russell Hancox
ff9cb34490 Project: avoid public visibility (#483) 2020-07-20 12:19:14 -04:00
Russell Hancox
60405f1e10 Fix some recent warnings (#482) 2020-07-20 11:36:25 -04:00
Edward Eigerman
ac9d3b2adf Update AboutWindow.xib (#481)
Remove the word "whitelist" from the user-facing window.
2020-07-17 22:11:23 -04:00
Russell Hancox
7e8bd46da3 Docs: fix readthedocs config (#480)
Fixes #479
2020-07-16 12:37:45 -04:00
Tom Burgin
2f6ed455e5 add fork and exit logging (#478)
* added fork and exit logging

* what did you use?

* review updates
2020-07-09 16:36:23 -04:00
Tom Burgin
8cb86b6d1d syncservice: create stub for syncservice (#477)
* stub for santasyncservice

* update protocol
2020-07-08 15:42:42 -04:00
Russell Hancox
fc074f6014 santactl: Make logging around rule download clearer (#476) 2020-07-08 10:09:56 -04:00
bfreezy
a7856e60e8 Add example System Extension and TCC configuration profiles (#474)
* add system extension policy example

* add tcc profile policy example

* set bundle ID to com.google.santa.daemon
2020-06-11 20:44:59 -04:00
Russell Hancox
41a40c9fbd Docs: remove whitelist/blacklist (#471) 2020-06-08 13:46:18 -04:00
Russell Hancox
8c18f6ebf5 Project: Update terminology in README (#470) 2020-06-08 12:41:44 -04:00
Tom Burgin
949053fedd update kext cache (#469) 2020-06-08 11:15:22 -04:00
Russell Hancox
8d2c39b71d Project: update whitelist/blacklist -> allowlist/blocklist (part 1: code) (#468) 2020-06-08 11:11:30 -04:00
Russell Hancox
8f872fb4fc Project: disable known deprecated warnings (#467) 2020-06-04 11:52:24 -04:00
Russell Hancox
5512f8cf19 santad/sysx: Prevent unlinking databases (#465)
* santad/sysx: Prevent unlinking databases
2020-06-01 13:21:30 -04:00
Russell Hancox
6742b38e31 santad: If database is locked don't attempt to unlink it (#466)
* santad: If database is locked don't attempt to unlink it
2020-05-29 17:22:23 -04:00
Russell Hancox
d1635f7e11 santad: Fix decision fetching for certs by hash (#464)
* santad: Fix decision fetching for certs by hash

Fixes #463
2020-05-11 11:43:07 -04:00
Tom Burgin
e2b865c081 prevent a dual duel (#462)
* prevent a dual duel

* bump version
2020-05-04 11:42:08 -04:00
Bradley Kemp
012b02de5d Update EventDetailURL docs
%bundle_id% and %bundle_ver% do not exist any more, they were removed by 6f417a1775 (diff-3250262f27ab2cb96ad4b47abdc9d51fL95-L108)
2020-05-01 07:22:57 -04:00
Russell Hancox
11ebead617 Add security policy link to README 2020-04-08 13:26:05 -04:00
Russell Hancox
e3fbabfe37 Create SECURITY.md 2020-04-08 13:26:05 -04:00
Russell Hancox
8757da7822 Version bump to 1.13 2020-04-07 17:14:02 -04:00
Russell Hancox
428582f471 santa-driver: fix use-after-free race in Get*MemoryDescriptor() 2020-04-07 17:14:02 -04:00
Russell Hancox
6e0effc0f4 santa-driver: fix off-by-one bug in externalMethod 2020-04-07 17:14:02 -04:00
Russell Hancox
683114fbec santa-driver: fix integer overflow/underflow in bucket_counts() 2020-04-07 17:14:02 -04:00
Tom Burgin
d9ebb4e3db version bump (#455) 2020-03-17 16:27:40 -04:00
Tom Burgin
e6aaf2f198 Santa.app: don't request SystemExtension loading (#454) 2020-03-17 16:23:48 -04:00
Tom Burgin
1c3757d4ab santactl: don't watch for config changes (#453)
* santactl: don't watch for config changes

* bump version
2020-03-16 18:40:36 -04:00
Tom Burgin
4346bb29c2 santactl: sanitize rule payload (#450)
* santactl: sanitize rule payload

* version bump
2020-02-27 15:16:40 -05:00
Tom Burgin
09655df8fc com.google.santa.daemon: reorder cleanup() (#448)
* com.google.santa.daemon: reorder cleanup()

* version bump
2020-02-26 15:13:51 -05:00
Tom Burgin
7504cd36e1 Simplify install scripts (#447)
* installer to respect EnableSystemExtension

* conform
2020-02-26 12:58:12 -05:00
106 changed files with 2450 additions and 882 deletions

25
.github/workflows/ci.yml vendored Normal file
View File

@@ -0,0 +1,25 @@
name: CI
on:
push:
paths-ignore:
- 'docs/**'
branches:
- '*'
pull_request:
paths-ignore:
- 'docs/**'
branches:
- main
jobs:
build:
runs-on: macos-latest
steps:
- uses: actions/checkout@v2
- name: Build Userspace
run: bazel build --apple_generate_dsym -c opt :release
- name: Build Driver
run: bazel build --apple_generate_dsym -c opt :release_driver
- name: Test
run: bazel test :unit_tests

View File

@@ -1,15 +0,0 @@
---
os: osx
osx_image: xcode11
language: objective-c
sudo: false
addons:
homebrew:
taps: bazelbuild/tap
packages: bazelbuild/tap/bazel
update: true
script:
- bazel build :release --show_progress_rate_limit=30.0 -c opt --apple_generate_dsym --color=no --verbose_failures --sandbox_debug
- bazel test :unit_tests --show_progress_rate_limit=30.0 --test_output=errors --color=no --verbose_failures --sandbox_debug

72
BUILD
View File

@@ -2,7 +2,7 @@ load("@build_bazel_rules_apple//apple:versioning.bzl", "apple_bundle_version")
load("//:helper.bzl", "run_command")
load("//:version.bzl", "SANTA_VERSION")
package(default_visibility = ["//visibility:public"])
package(default_visibility = ["//:santa_package_group"])
licenses(["notice"])
@@ -21,6 +21,12 @@ config_setting(
values = {"compilation_mode": "opt"},
)
package_group(
name = "santa_package_group",
packages = ["//..."],
)
################################################################################
# Loading/Unloading/Reloading
################################################################################
@@ -54,9 +60,9 @@ set -e
rm -rf /tmp/bazel_santa_reload
unzip -d /tmp/bazel_santa_reload \
$${BUILD_WORKSPACE_DIRECTORY}/bazel-bin/Source/santa_driver/santa_driver.zip >/dev/null
$${BUILD_WORKSPACE_DIRECTORY}/bazel-out/*/bin/Source/santa_driver/santa_driver.zip >/dev/null
unzip -d /tmp/bazel_santa_reload \
$${BUILD_WORKSPACE_DIRECTORY}/bazel-bin/Source/santa/Santa.zip >/dev/null
$${BUILD_WORKSPACE_DIRECTORY}/bazel-out/*/bin/Source/santa/Santa.zip >/dev/null
echo "You may be asked for your password for sudo"
sudo BINARIES=/tmp/bazel_santa_reload CONF=$${BUILD_WORKSPACE_DIRECTORY}/Conf \
$${BUILD_WORKSPACE_DIRECTORY}/Conf/install.sh
@@ -72,7 +78,6 @@ genrule(
name = "release",
srcs = [
"//Source/santa:Santa",
"//Source/santa_driver",
"Conf/install.sh",
"Conf/uninstall.sh",
"Conf/com.google.santa.bundleservice.plist",
@@ -91,9 +96,9 @@ genrule(
echo "Please add '-c opt' flag to bazel invocation"
""",
":opt_build": """
# Extract santa_driver.zip and Santa.zip
# Extract Santa.zip
for SRC in $(SRCS); do
if [ "$$(basename $${SRC})" == "santa_driver.zip" -o "$$(basename $${SRC})" == "Santa.zip" ]; then
if [ "$$(basename $${SRC})" == "Santa.zip" ]; then
mkdir -p $(@D)/binaries
unzip -q $${SRC} -d $(@D)/binaries >/dev/null
fi
@@ -110,10 +115,6 @@ genrule(
# Gather together the dSYMs. Throw an error if no dSYMs were found
for SRC in $(SRCS); do
case $${SRC} in
*santa-driver.kext.dSYM*Info.plist)
mkdir -p $(@D)/dsym
cp -LR $$(dirname $$(dirname $${SRC})) $(@D)/dsym/santa-driver.kext.dSYM
;;
*santad.dSYM*Info.plist)
mkdir -p $(@D)/dsym
cp -LR $$(dirname $$(dirname $${SRC})) $(@D)/dsym/santad.dSYM
@@ -156,12 +157,61 @@ genrule(
heuristic_label_expansion = 0,
)
genrule(
name = "release_driver",
srcs = [
"//Source/santa_driver",
],
outs = ["santa-driver-" + SANTA_VERSION + ".tar.gz"],
cmd = select({
"//conditions:default": """
echo "ERROR: Trying to create a release tarball without optimization."
echo "Please add '-c opt' flag to bazel invocation"
""",
":opt_build": """
# Extract santa_driver.zip
for SRC in $(SRCS); do
if [ "$$(basename $${SRC})" == "santa_driver.zip" ]; then
mkdir -p $(@D)/binaries
unzip -q $${SRC} -d $(@D)/binaries >/dev/null
fi
done
# Gather together the dSYMs. Throw an error if no dSYMs were found
for SRC in $(SRCS); do
case $${SRC} in
*santa-driver.kext.dSYM*Info.plist)
mkdir -p $(@D)/dsym
cp -LR $$(dirname $$(dirname $${SRC})) $(@D)/dsym/santa-driver.kext.dSYM
;;
esac
done
# Cause a build failure if the dSYMs are missing.
if [[ ! -d "$(@D)/dsym" ]]; then
echo "dsym dir missing: Did you forget to use --apple_generate_dsym?"
echo "This flag is required for the 'release' target."
exit 1
fi
# Update all the timestamps to now. Bazel avoids timestamps to allow
# builds to be hermetic and cacheable but for releases we want the
# timestamps to be more-or-less correct.
find $(@D)/{binaries,dsym} -exec touch {} \\;
# Create final output tar
tar -C $(@D) -czpf $(@) binaries dsym
""",
}),
heuristic_label_expansion = 0,
)
test_suite(
name = "unit_tests",
tests = [
"//Source/common:SantaCacheTest",
"//Source/common:SNTFileInfoTest",
"//Source/common:SNTPrefixTreeTest",
"//Source/santa_driver:SantaCacheTest",
"//Source/santactl:SNTCommandFileInfoTest",
"//Source/santactl:SNTCommandSyncTest",
"//Source/santad:SNTEventTableTest",

View File

@@ -13,18 +13,15 @@ approved it, but you must do it before we can put your code into our codebase.
Before you start working on a larger contribution, you should get in touch with
us first through the [issue tracker](https://github.com/google/santa/issues)
with your idea so that we can help out and possibly guide you. Coordinating up
front makes it much easier to avoid frustration later on.
with your idea so that we can help out and possibly guide you. Co-ordinating
large changes ahead of time can avoid frustration later on.
### Code reviews
All submissions, including submissions by project members, require review. We
use GitHub pull requests for this purpose. It's also a good idea to run the
tests beforehand, which you can do with the following commands:
All submissions - including submissions by project members - require review. We
use GitHub pull requests for this purpose. GitHub will automatically run the
tests when you mail your pull request and a proper review won't be started until
the tests are complete and passing.
```sh
rake tests:logic
rake tests:kernel # only necessary if you're changing the kext code
```
### Code Style
All code submissions should try to match the surrounding code. Wherever possible,

View File

@@ -1,6 +1,6 @@
#!/bin/bash
# Load the kernel extension, santad, sync client
# Load com.google.santa.daemon and com.google.santa.bundleservice
# If a user is logged in, also load the GUI agent.
# If the target volume is not /, do nothing
@@ -13,24 +13,19 @@
mkdir -p /usr/local/bin
/bin/ln -sf /Applications/Santa.app/Contents/MacOS/santactl /usr/local/bin/santactl
if [ $(uname -r | cut -d'.' -f1) -ge 19 ]; then
# Running on 10.15+
echo "Santa postinstall: running on 10.15+"
/bin/rm -rf /Library/Extensions/santa-driver.kext
/bin/rm -f /Library/LaunchDaemons/com.google.santad.plist
else
# Running on <10.15
/bin/launchctl load -w /Library/LaunchDaemons/com.google.santad.plist
fi
# Remove the kext before com.google.santa.daemon loads if the SystemExtension is already present.
# This prevents Santa from dueling itself if the "EnableSystemExtension" config is set to false.
/bin/launchctl list EQHXZ8M8AV.com.google.santa.daemon > /dev/null 2>&1 && rm -rf /Library/Extensions/santa-driver.kext
# Load the bundle service
# Load com.google.santa.daemon, its main has logic to handle loading the kext
# or relaunching itself as a SystemExtension.
/bin/launchctl load -w /Library/LaunchDaemons/com.google.santad.plist
# Load com.google.santa.bundleservice
/bin/launchctl load -w /Library/LaunchDaemons/com.google.santa.bundleservice.plist
user=$(/usr/bin/stat -f '%u' /dev/console)
if [[ -z "$user" ]]; then
/Applications/Santa.app/Contents/MacOS/Santa --load-system-extension
exit 0
fi
/bin/launchctl asuser ${user} /bin/launchctl load /Library/LaunchAgents/com.google.santa.plist
GUI_USER=$(/usr/bin/stat -f '%u' /dev/console)
[[ -z "${GUI_USER}" ]] && exit 0
/bin/launchctl asuser "${GUI_USER}" /bin/launchctl load /Library/LaunchAgents/com.google.santa.plist
exit 0

View File

@@ -19,11 +19,13 @@
/bin/launchctl remove com.google.santasync
/bin/rm -f /Library/LaunchDaemons/com.google.santasync.plist
/bin/rm -rf /Applications/Santa.app
/bin/rm -rf /Library/Extensions/santa-driver.kext
/bin/sleep 1
user=$(/usr/bin/stat -f '%u' /dev/console)
[[ -n "$user" ]] && /bin/launchctl asuser ${user} /bin/launchctl remove com.google.santagui
[[ -n "$user" ]] && /bin/launchctl asuser ${user} /bin/launchctl remove com.google.santa
GUI_USER=$(/usr/bin/stat -f '%u' /dev/console)
[[ -z "${GUI_USER}" ]] && exit 0
/bin/launchctl asuser "${GUI_USER}" /bin/launchctl remove com.google.santagui
/bin/launchctl asuser "${GUI_USER}" /bin/launchctl remove com.google.santa
exit 0

View File

@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.google.santa.syncservice</string>
<key>ProgramArguments</key>
<array>
<string>/Applications/Santa.app/Contents/MacOS/santasyncservice</string>
<string>--syslog</string>
</array>
<key>MachServices</key>
<dict>
<key>com.google.santa.syncservice</key>
<true/>
</dict>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<true/>
</dict>
</plist>

View File

@@ -31,10 +31,10 @@ fi
GUI_USER=$(/usr/bin/stat -f '%u' /dev/console)
# Unload GUI agent if someone is logged in.
[[ -n "${GUI_USER}" ]] && \
/bin/launchctl asuser "${GUI_USER}" /bin/launchctl remove com.google.santagui
[[ -n "$GUI_USER" ]] && \
/bin/launchctl asuser ${GUI_USER} /bin/launchctl remove com.google.santagui
[[ -n "$GUI_USER" ]] && \
/bin/launchctl asuser ${GUI_USER} /bin/launchctl remove com.google.santa
/bin/launchctl asuser "${GUI_USER}" /bin/launchctl remove com.google.santa
# Cleanup cruft from old versions
/bin/launchctl remove com.google.santasync >/dev/null 2>&1
@@ -49,33 +49,30 @@ GUI_USER=$(/usr/bin/stat -f '%u' /dev/console)
/bin/cp -r ${BINARIES}/Santa.app /Applications
# Only copy the kext if the SystemExtension is not present.
# This prevents Santa from dueling itself if the "EnableSystemExtension" config is set to false.
/bin/launchctl list EQHXZ8M8AV.com.google.santa.daemon > /dev/null 2>&1 || /bin/cp -r ${BINARIES}/santa-driver.kext /Library/Extensions && /usr/sbin/kextcache -update-volume / -bundle-id com.google.santa-driver
/bin/mkdir -p /usr/local/bin
/bin/ln -s /Applications/Santa.app/Contents/MacOS/santactl /usr/local/bin 2>/dev/null
/bin/cp ${CONF}/com.google.santa.plist /Library/LaunchAgents
/bin/cp ${CONF}/com.google.santa.bundleservice.plist /Library/LaunchDaemons
/bin/cp ${CONF}/com.google.santad.plist /Library/LaunchDaemons
/bin/cp ${CONF}/com.google.santa.asl.conf /etc/asl/
/bin/cp ${CONF}/com.google.santa.newsyslog.conf /etc/newsyslog.d/
# Reload syslogd to pick up ASL configuration change.
/usr/bin/killall -HUP syslogd
# Only copy the kext and load santad if running pre-10.15
if [ $(uname -r | cut -d'.' -f1) -lt 19 ]; then
/bin/cp -r ${BINARIES}/santa-driver.kext /Library/Extensions
/bin/cp ${CONF}/com.google.santad.plist /Library/LaunchDaemons
/bin/launchctl load /Library/LaunchDaemons/com.google.santad.plist
else
/Applications/Santa.app/Contents/MacOS/Santa --load-system-extension
fi
# Load com.google.santa.daemon
/bin/launchctl load /Library/LaunchDaemons/com.google.santad.plist
# Load the bundle service
# Load com.google.santa.bundleservice
/bin/launchctl load /Library/LaunchDaemons/com.google.santa.bundleservice.plist
# Load GUI agent if someone is logged in.
if [[ -n "$GUI_USER" ]]; then
/bin/launchctl asuser ${GUI_USER} \
/bin/launchctl load -w /Library/LaunchAgents/com.google.santa.plist
fi
[[ -z "${GUI_USER}" ]] && exit 0
/bin/launchctl asuser "${GUI_USER}" /bin/launchctl load -w /Library/LaunchAgents/com.google.santa.plist
exit 0

View File

@@ -7,7 +7,7 @@
[ "$EUID" != 0 ] && printf "%s\n" "This requires running as root/sudo." && exit 1
# For macOS 10.15+ this will block up to 60 seconds
/Applications/Santa.app/Contents/MacOS/Santa --unload-system-extension
/bin/launchctl list EQHXZ8M8AV.com.google.santa.daemon > /dev/null 2>&1 && /Applications/Santa.app/Contents/MacOS/Santa --unload-system-extension
/bin/launchctl remove com.google.santad
sleep 1

View File

@@ -23,7 +23,7 @@ DEPENDENCIES:
- OCMock
SPEC REPOS:
https://github.com/cocoapods/specs.git:
https://github.com/CocoaPods/Specs.git:
- FMDB
- MOLAuthenticatingURLSession
- MOLCertificate
@@ -43,4 +43,4 @@ SPEC CHECKSUMS:
PODFILE CHECKSUM: d03767a9915896232523962c98d9ff7294aec2b7
COCOAPODS: 1.7.5
COCOAPODS: 1.10.0

View File

@@ -1,19 +1,15 @@
# Santa [![Build Status][build-status-img]][build-status-link] [![Documentation Status][doc-status-img]][doc-status-link]
[build-status-img]: https://travis-ci.org/google/santa.png?branch=master
[build-status-link]: https://travis-ci.org/google/santa
[doc-status-img]: https://readthedocs.org/projects/santa/badge/?version=latest
[doc-status-link]: https://santa.readthedocs.io/en/latest/?badge=latest
# Santa ![CI](https://github.com/google/santa/workflows/CI/badge.svg?branch=main)
<p align="center">
<img src="./Source/santa/Resources/Images.xcassets/AppIcon.appiconset/santa-hat-icon-128.png" alt="Santa Icon" />
</p>
Santa is a binary whitelisting/blacklisting system for macOS. It consists of a
kernel extension (or a system extension on macOS 10.15+) 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 managing the system and synchronizing the database with a server.
Santa is a binary authorization system for macOS. It consists of a kernel
extension (or a system extension on macOS 10.15+) 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 managing the system and synchronizing the
database with a server.
It is named Santa because it keeps track of binaries that are naughty or nice.
@@ -38,26 +34,29 @@ If you believe you have a bug, feel free to report [an
issue](https://github.com/google/santa/isues) and we'll respond as soon as we
can.
If you believe you've found a vulnerability, please read the
[security policy](https://github.com/google/santa/security/policy) for
disclosure reporting.
# Admin-Related Features
* Multiple modes: In the default MONITOR mode, all binaries except those marked
as blacklisted will be allowed to run, whilst being logged and recorded in
the events database. In LOCKDOWN mode, only whitelisted binaries are allowed
to run.
as blocked will be allowed to run, whilst being logged and recorded in
the events database. In LOCKDOWN mode, only listed binaries are allowed to
run.
* Event logging: When the kext is loaded, all binary launches are logged. When
in either mode, all unknown or denied binaries are stored in the database to
enable later aggregation.
* Certificate-based rules, with override levels: Instead of relying on a
binary's hash (or 'fingerprint'), executables can be whitelisted/blacklisted
by their signing certificate. You can therefore trust/block all binaries by a
binary's hash (or 'fingerprint'), executables can be allowed/blocked by their
signing certificate. You can therefore allow/block all binaries by a
given publisher that were signed with that cert across version updates. A
binary can only be whitelisted by its certificate if its signature validates
correctly, but a rule for a binary's fingerprint will override a decision for
a certificate; i.e. you can whitelist a certificate while blacklisting a
binary signed with that certificate, or vice-versa.
binary can only be allowed by its certificate if its signature validates
correctly but a rule for a binary's fingerprint will override a decision for
a certificate; i.e. you can allowlist a certificate while blocking a binary
signed with that certificate, or vice-versa.
* Path-based rules (via NSRegularExpression/ICU): This allows a similar feature
to that found in Managed Client (the precursor to configuration profiles,
@@ -70,10 +69,10 @@ can.
* Failsafe cert rules: You cannot put in a deny rule that would block the
certificate used to sign launchd, a.k.a. pid 1, and therefore all components
used in macOS. The binaries in every OS update (and in some cases entire new
versions) are therefore auto-whitelisted. This does not affect binaries from
Apple's App Store, which use various certs that change regularly for common
apps. Likewise, you cannot blacklist Santa itself, and Santa uses a distinct
separate cert than other Google apps.
versions) are therefore automatically allowed. This does not affect binaries
from Apple's App Store, which use various certs that change regularly for
common apps. Likewise, you cannot block Santa itself, and Santa uses a
distinct separate cert than other Google apps.
# Intentions and Expectations
@@ -90,7 +89,7 @@ protect hosts in whatever other ways you see fit.
# Security and Performance-Related Features
* In-kernel caching: whitelisted binaries are cached in the kernel so the
* In-kernel caching: allowed binaries are cached in the kernel so the
processing required to make a request is only done if the binary isn't
already cached.
@@ -125,7 +124,7 @@ protect hosts in whatever other ways you see fit.
binary. This is because after weighing the administration cost vs the
benefit, we found it wasn't worthwhile. Additionally, a number of
applications make use of temporary generated scripts, which we can't possibly
whitelist and not doing so would cause problems. We're happy to revisit this
allowlist and not doing so would cause problems. We're happy to revisit this
(or at least make it an option) if it would be useful to others.
# Sync Servers
@@ -141,6 +140,9 @@ protect hosts in whatever other ways you see fit.
* [Zentral](https://github.com/zentralopensource/zentral/wiki) - A
centralized service that pulls data from multiple sources and deploy
configurations to multiple services.
* [Zercurity](https://github.com/zercurity/zercurity) - A dockerized service
for managing and monitoring applications across a large fleet utilizing
Santa + Osquery.
* Alternatively, `santactl` can configure rules locally (without a sync
server).
@@ -150,8 +152,8 @@ protect hosts in whatever other ways you see fit.
A tool like Santa doesn't really lend itself to screenshots, so here's a video
instead.
<p align="center"> <img src="https://zippy.gfycat.com/MadFatalAmphiuma.gif"
alt="Santa Block Video" /> </p>
<p align="center"> <img src="https://thumbs.gfycat.com/MadFatalAmphiuma-small.gif" alt="Santa Block Video" /> </p>
# Kext Signing
Kernel extensions on macOS 10.9 and later must be signed using an Apple-provided

12
SECURITY.md Normal file
View File

@@ -0,0 +1,12 @@
# Reporting a Vulnerability
If you believe you have found a security vulnerability, we would appreciate private disclosure
so that we can work on a fix before disclosure. Any vulnerabilities reported to us will be
disclosed publicly either when a new version with fixes is released or 90 days has passed,
whichever comes first.
To report vulnerabilities to us privately, please e-mail `santa-team@google.com`.
If you want to encrypt your e-mail, you can use our GPG key `0x92AFE41DAB49BBB6`
available on pool.sks-keyservers.net:
`gpg --keyserver pool.sks-keyservers.net --recv-key 0x92AFE41DAB49BBB6`

View File

@@ -10,6 +10,7 @@
0D9F577C2342650F005D9AA8 /* SNTPrefixTree.cc in Sources */ = {isa = PBXBuildFile; fileRef = C7658B022322B84F00F36578 /* SNTPrefixTree.cc */; };
59502195B2982225D3706DCE /* libPods-santabundleservice.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 2A55D73A235850B9FA991865 /* libPods-santabundleservice.a */; };
AD3736AF78C41A962C26D429 /* libPods-Santa.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C3E743944A9D77423AA1534 /* libPods-Santa.a */; };
B617F8907035AD3DA2CB5C45 /* libPods-syncservice.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D10E53C5ACA15304D9A7CC95 /* libPods-syncservice.a */; };
C71E472F22F0F97B00921CD9 /* com.google.santa.daemon in CopyFiles */ = {isa = PBXBuildFile; fileRef = C779C4E622F0F51400EE2541 /* com.google.santa.daemon */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
C71E473122F0FAA100921CD9 /* com.google.santa.daemon.systemextension in CopyFiles */ = {isa = PBXBuildFile; fileRef = C7A8308022F0F81F00F856AC /* com.google.santa.daemon.systemextension */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
C72ED2B62324962400255555 /* SNTEndpointSecurityManager.mm in Sources */ = {isa = PBXBuildFile; fileRef = C72ED2B52324962400255555 /* SNTEndpointSecurityManager.mm */; };
@@ -50,7 +51,6 @@
C7658B352322C0A000F36578 /* SNTXPCBundleServiceInterface.m in Sources */ = {isa = PBXBuildFile; fileRef = C7658ACC2322B84F00F36578 /* SNTXPCBundleServiceInterface.m */; };
C7658B362322C0A300F36578 /* SNTXPCControlInterface.m in Sources */ = {isa = PBXBuildFile; fileRef = C7658ACA2322B84F00F36578 /* SNTXPCControlInterface.m */; };
C7658B372322C0B000F36578 /* SNTXPCNotifierInterface.m in Sources */ = {isa = PBXBuildFile; fileRef = C7658ACF2322B84F00F36578 /* SNTXPCNotifierInterface.m */; };
C7658B382322C0B400F36578 /* SNTXPCSyncdInterface.m in Sources */ = {isa = PBXBuildFile; fileRef = C7658AC22322B84F00F36578 /* SNTXPCSyncdInterface.m */; };
C7658B392322C0B800F36578 /* SNTXPCUnprivilegedControlInterface.m in Sources */ = {isa = PBXBuildFile; fileRef = C7658AC52322B84F00F36578 /* SNTXPCUnprivilegedControlInterface.m */; };
C7658B3A2322C0C200F36578 /* SNTSystemInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = C7658AD12322B84F00F36578 /* SNTSystemInfo.m */; };
C7658B3B2322C0E600F36578 /* SNTBlockMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = C7658AC72322B84F00F36578 /* SNTBlockMessage.m */; };
@@ -92,9 +92,10 @@
C7658B602322C2CB00F36578 /* SNTSystemInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = C7658AD12322B84F00F36578 /* SNTSystemInfo.m */; };
C7658B612322C2DA00F36578 /* SNTLogging.m in Sources */ = {isa = PBXBuildFile; fileRef = C7658AD82322B84F00F36578 /* SNTLogging.m */; };
C7658B622322C2E100F36578 /* SNTXPCControlInterface.m in Sources */ = {isa = PBXBuildFile; fileRef = C7658ACA2322B84F00F36578 /* SNTXPCControlInterface.m */; };
C7658B632322C2E400F36578 /* SNTXPCSyncdInterface.m in Sources */ = {isa = PBXBuildFile; fileRef = C7658AC22322B84F00F36578 /* SNTXPCSyncdInterface.m */; };
C7658B642322C2F300F36578 /* SNTXPCUnprivilegedControlInterface.m in Sources */ = {isa = PBXBuildFile; fileRef = C7658AC52322B84F00F36578 /* SNTXPCUnprivilegedControlInterface.m */; };
C7658B652322C30F00F36578 /* santactl in CopyFiles */ = {isa = PBXBuildFile; fileRef = C7658B0C2322B95500F36578 /* santactl */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
C7CC459124B618780018C05C /* SNTXPCSyncdInterface.m in Sources */ = {isa = PBXBuildFile; fileRef = C7CC459024B6184F0018C05C /* SNTXPCSyncdInterface.m */; };
C7CC459224B6188B0018C05C /* SNTXPCSyncdInterface.m in Sources */ = {isa = PBXBuildFile; fileRef = C7CC459024B6184F0018C05C /* SNTXPCSyncdInterface.m */; };
C7CDA6FB233E73D20013622B /* SNTXPCBundleServiceInterface.m in Sources */ = {isa = PBXBuildFile; fileRef = C7658ACC2322B84F00F36578 /* SNTXPCBundleServiceInterface.m */; };
C7CDA6FC233E73D80013622B /* SNTFileInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = C7658AD02322B84F00F36578 /* SNTFileInfo.m */; };
C7CDA6FD233E73E40013622B /* SNTStoredEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = C7658ADC2322B84F00F36578 /* SNTStoredEvent.m */; };
@@ -108,6 +109,14 @@
C7F5C1AE233E72CC00A3F7FD /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = C7658AF62322B84F00F36578 /* main.m */; };
C7F5C1AF233E72CF00A3F7FD /* SNTBundleService.m in Sources */ = {isa = PBXBuildFile; fileRef = C7658AF22322B84F00F36578 /* SNTBundleService.m */; };
C7F5C1B0233E735E00A3F7FD /* santabundleservice in CopyFiles */ = {isa = PBXBuildFile; fileRef = C7F5C1A7233E72BC00A3F7FD /* santabundleservice */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
C7FA384524B6167800D192F9 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = C7FA383324B60F3300D192F9 /* main.m */; };
C7FA384624B6167800D192F9 /* SNTSyncService.h in Sources */ = {isa = PBXBuildFile; fileRef = C7FA383424B60F7600D192F9 /* SNTSyncService.h */; };
C7FA384724B6167800D192F9 /* SNTSyncService.m in Sources */ = {isa = PBXBuildFile; fileRef = C7FA383524B60F7600D192F9 /* SNTSyncService.m */; };
C7FA384824B6169400D192F9 /* SNTLogging.m in Sources */ = {isa = PBXBuildFile; fileRef = C7658AD82322B84F00F36578 /* SNTLogging.m */; };
C7FA384924B6169400D192F9 /* SNTStoredEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = C7658ADC2322B84F00F36578 /* SNTStoredEvent.m */; };
C7FA384A24B6169400D192F9 /* SNTXPCSyncServiceInterface.m in Sources */ = {isa = PBXBuildFile; fileRef = C7FA383724B60FF800D192F9 /* SNTXPCSyncServiceInterface.m */; };
C7FACBFA25646FE500CCB198 /* SNTConfigurator.m in Sources */ = {isa = PBXBuildFile; fileRef = C7658ACD2322B84F00F36578 /* SNTConfigurator.m */; };
C7FACC0225646FEB00CCB198 /* SNTSystemInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = C7658AD12322B84F00F36578 /* SNTSystemInfo.m */; };
D28CA4C618C62392319BB642 /* libPods-santactl.a in Frameworks */ = {isa = PBXBuildFile; fileRef = B7714ABC7F247685608DACE7 /* libPods-santactl.a */; };
D698C8C9E47554577ED4939F /* libPods-com.google.santa.daemon.a in Frameworks */ = {isa = PBXBuildFile; fileRef = C05F6AD95EB704B20828BDA1 /* libPods-com.google.santa.daemon.a */; };
F5F5D1EF2AF051FEA97A3A59 /* libPods-sysx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 91FF0B4E62F1E90A88478993 /* libPods-sysx.a */; };
@@ -181,6 +190,15 @@
);
runOnlyForDeploymentPostprocessing = 1;
};
C7FA383A24B6136C00D192F9 /* CopyFiles */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = /usr/share/man/man1/;
dstSubfolderSpec = 0;
files = (
);
runOnlyForDeploymentPostprocessing = 1;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
@@ -189,9 +207,11 @@
18183794C94BAEAD167B12EC /* Pods-santad.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-santad.debug.xcconfig"; path = "Target Support Files/Pods-santad/Pods-santad.debug.xcconfig"; sourceTree = "<group>"; };
24CDFD218D8B35E34895AA6A /* libPods-santaxpcproxy.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-santaxpcproxy.a"; sourceTree = BUILT_PRODUCTS_DIR; };
2A55D73A235850B9FA991865 /* libPods-santabundleservice.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-santabundleservice.a"; sourceTree = BUILT_PRODUCTS_DIR; };
4A98E2E9727FBEF27CDDA298 /* Pods-syncservice.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-syncservice.debug.xcconfig"; path = "Target Support Files/Pods-syncservice/Pods-syncservice.debug.xcconfig"; sourceTree = "<group>"; };
4C3E743944A9D77423AA1534 /* libPods-Santa.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Santa.a"; sourceTree = BUILT_PRODUCTS_DIR; };
4E28DBA012524ABF55F8300C /* Pods-com.google.santa.daemon.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-com.google.santa.daemon.debug.xcconfig"; path = "Target Support Files/Pods-com.google.santa.daemon/Pods-com.google.santa.daemon.debug.xcconfig"; sourceTree = "<group>"; };
7AF15DF785BAA0EAB0BE340D /* Pods-santad.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-santad.release.xcconfig"; path = "Target Support Files/Pods-santad/Pods-santad.release.xcconfig"; sourceTree = "<group>"; };
7FEBB0D42E35B93E5B995B06 /* Pods-syncservice.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-syncservice.release.xcconfig"; path = "Target Support Files/Pods-syncservice/Pods-syncservice.release.xcconfig"; sourceTree = "<group>"; };
91FF0B4E62F1E90A88478993 /* libPods-sysx.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-sysx.a"; sourceTree = BUILT_PRODUCTS_DIR; };
B7714ABC7F247685608DACE7 /* libPods-santactl.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-santactl.a"; sourceTree = BUILT_PRODUCTS_DIR; };
C05543B3701F50CA798B4B11 /* Pods-sysx.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-sysx.release.xcconfig"; path = "Target Support Files/Pods-sysx/Pods-sysx.release.xcconfig"; sourceTree = "<group>"; };
@@ -291,7 +311,6 @@
C7658ABF2322B84F00F36578 /* SNTCommonEnums.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SNTCommonEnums.h; sourceTree = "<group>"; };
C7658AC02322B84F00F36578 /* SNTSystemInfo.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SNTSystemInfo.h; sourceTree = "<group>"; };
C7658AC12322B84F00F36578 /* SNTFileInfo.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SNTFileInfo.h; sourceTree = "<group>"; };
C7658AC22322B84F00F36578 /* SNTXPCSyncdInterface.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SNTXPCSyncdInterface.m; sourceTree = "<group>"; };
C7658AC32322B84F00F36578 /* SNTStrengthify.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SNTStrengthify.h; sourceTree = "<group>"; };
C7658AC42322B84F00F36578 /* SNTCachedDecision.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SNTCachedDecision.m; sourceTree = "<group>"; };
C7658AC52322B84F00F36578 /* SNTXPCUnprivilegedControlInterface.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SNTXPCUnprivilegedControlInterface.m; sourceTree = "<group>"; };
@@ -312,7 +331,6 @@
C7658AD42322B84F00F36578 /* SNTXPCUnprivilegedControlInterface.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SNTXPCUnprivilegedControlInterface.h; sourceTree = "<group>"; };
C7658AD52322B84F00F36578 /* BUILD */ = {isa = PBXFileReference; lastKnownFileType = text; path = BUILD; sourceTree = "<group>"; };
C7658AD62322B84F00F36578 /* SNTCachedDecision.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SNTCachedDecision.h; sourceTree = "<group>"; };
C7658AD72322B84F00F36578 /* SNTXPCSyncdInterface.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SNTXPCSyncdInterface.h; sourceTree = "<group>"; };
C7658AD82322B84F00F36578 /* SNTLogging.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SNTLogging.m; sourceTree = "<group>"; };
C7658AD92322B84F00F36578 /* SNTFileInfoTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SNTFileInfoTest.m; sourceTree = "<group>"; };
C7658ADA2322B84F00F36578 /* SNTXPCControlInterface.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SNTXPCControlInterface.h; sourceTree = "<group>"; };
@@ -358,14 +376,25 @@
C779C2DE22F0E95000EE2541 /* Santa.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Santa.app; sourceTree = BUILT_PRODUCTS_DIR; };
C779C4E622F0F51400EE2541 /* com.google.santa.daemon */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = com.google.santa.daemon; sourceTree = BUILT_PRODUCTS_DIR; };
C7A8308022F0F81F00F856AC /* com.google.santa.daemon.systemextension */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = com.google.santa.daemon.systemextension; sourceTree = BUILT_PRODUCTS_DIR; };
C7CC458F24B6184F0018C05C /* SNTXPCSyncdInterface.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SNTXPCSyncdInterface.h; sourceTree = "<group>"; };
C7CC459024B6184F0018C05C /* SNTXPCSyncdInterface.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SNTXPCSyncdInterface.m; sourceTree = "<group>"; };
C7D35DDA2322C902000C5EB4 /* santa-driver.kext */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "santa-driver.kext"; sourceTree = BUILT_PRODUCTS_DIR; };
C7F5C1A7233E72BC00A3F7FD /* santabundleservice */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = santabundleservice; sourceTree = BUILT_PRODUCTS_DIR; };
C7FA383324B60F3300D192F9 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
C7FA383424B60F7600D192F9 /* SNTSyncService.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SNTSyncService.h; sourceTree = "<group>"; };
C7FA383524B60F7600D192F9 /* SNTSyncService.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SNTSyncService.m; sourceTree = "<group>"; };
C7FA383624B60FF800D192F9 /* SNTXPCSyncServiceInterface.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SNTXPCSyncServiceInterface.h; sourceTree = "<group>"; };
C7FA383724B60FF800D192F9 /* SNTXPCSyncServiceInterface.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SNTXPCSyncServiceInterface.m; sourceTree = "<group>"; };
C7FA383C24B6136C00D192F9 /* syncservice */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = syncservice; sourceTree = BUILT_PRODUCTS_DIR; };
C7FA384324B6146600D192F9 /* BUILD */ = {isa = PBXFileReference; lastKnownFileType = text; path = BUILD; sourceTree = "<group>"; };
C7FA384424B6146600D192F9 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
C7FBD1242396CACE005A0F6D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
C7FBD1252396CACE005A0F6D /* Santa.app.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Santa.app.entitlements; sourceTree = "<group>"; };
C7FBD1262396CB17005A0F6D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
C7FBD1272396CB62005A0F6D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
C7FBD1282396CB62005A0F6D /* com.google.santa.daemon.systemextension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = com.google.santa.daemon.systemextension.entitlements; sourceTree = "<group>"; };
CD71F19EA875F61754E81EBF /* Pods-Santa.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Santa.release.xcconfig"; path = "Target Support Files/Pods-Santa/Pods-Santa.release.xcconfig"; sourceTree = "<group>"; };
D10E53C5ACA15304D9A7CC95 /* libPods-syncservice.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-syncservice.a"; sourceTree = BUILT_PRODUCTS_DIR; };
D4808D8635FB5E8E5F4637BB /* Pods-santabundleservice.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-santabundleservice.debug.xcconfig"; path = "Target Support Files/Pods-santabundleservice/Pods-santabundleservice.debug.xcconfig"; sourceTree = "<group>"; };
D7360306D7CFDD179D003266 /* Pods-sysx.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-sysx.debug.xcconfig"; path = "Target Support Files/Pods-sysx/Pods-sysx.debug.xcconfig"; sourceTree = "<group>"; };
D979E8ECE019FB93D1D381E7 /* Pods-santaxpcproxy.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-santaxpcproxy.release.xcconfig"; path = "Target Support Files/Pods-santaxpcproxy/Pods-santaxpcproxy.release.xcconfig"; sourceTree = "<group>"; };
@@ -425,6 +454,14 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
C7FA383924B6136C00D192F9 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
B617F8907035AD3DA2CB5C45 /* libPods-syncservice.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
@@ -449,6 +486,7 @@
C7658AF12322B84F00F36578 /* santabundleservice */,
C7658A822322B84F00F36578 /* santactl */,
C7658A5A2322B84F00F36578 /* santad */,
C7FA383224B60EFB00D192F9 /* santasyncservice */,
);
path = Source;
sourceTree = "<group>";
@@ -620,8 +658,10 @@
C7658ACA2322B84F00F36578 /* SNTXPCControlInterface.m */,
C7658AB12322B84F00F36578 /* SNTXPCNotifierInterface.h */,
C7658ACF2322B84F00F36578 /* SNTXPCNotifierInterface.m */,
C7658AD72322B84F00F36578 /* SNTXPCSyncdInterface.h */,
C7658AC22322B84F00F36578 /* SNTXPCSyncdInterface.m */,
C7CC458F24B6184F0018C05C /* SNTXPCSyncdInterface.h */,
C7CC459024B6184F0018C05C /* SNTXPCSyncdInterface.m */,
C7FA383624B60FF800D192F9 /* SNTXPCSyncServiceInterface.h */,
C7FA383724B60FF800D192F9 /* SNTXPCSyncServiceInterface.m */,
C7658AD42322B84F00F36578 /* SNTXPCUnprivilegedControlInterface.h */,
C7658AC52322B84F00F36578 /* SNTXPCUnprivilegedControlInterface.m */,
C7658AB42322B84F00F36578 /* testdata */,
@@ -758,10 +798,23 @@
C7658B0C2322B95500F36578 /* santactl */,
C7D35DDA2322C902000C5EB4 /* santa-driver.kext */,
C7F5C1A7233E72BC00A3F7FD /* santabundleservice */,
C7FA383C24B6136C00D192F9 /* syncservice */,
);
name = Products;
sourceTree = "<group>";
};
C7FA383224B60EFB00D192F9 /* santasyncservice */ = {
isa = PBXGroup;
children = (
C7FA384324B6146600D192F9 /* BUILD */,
C7FA384424B6146600D192F9 /* Info.plist */,
C7FA383324B60F3300D192F9 /* main.m */,
C7FA383424B60F7600D192F9 /* SNTSyncService.h */,
C7FA383524B60F7600D192F9 /* SNTSyncService.m */,
);
path = santasyncservice;
sourceTree = "<group>";
};
D2DA9449115697B603A40259 /* Frameworks */ = {
isa = PBXGroup;
children = (
@@ -774,6 +827,7 @@
2A55D73A235850B9FA991865 /* libPods-santabundleservice.a */,
B7714ABC7F247685608DACE7 /* libPods-santactl.a */,
C05F6AD95EB704B20828BDA1 /* libPods-com.google.santa.daemon.a */,
D10E53C5ACA15304D9A7CC95 /* libPods-syncservice.a */,
);
name = Frameworks;
sourceTree = "<group>";
@@ -795,6 +849,8 @@
0A60226B8B4F01BE817BAAA3 /* Pods-santactl.release.xcconfig */,
4E28DBA012524ABF55F8300C /* Pods-com.google.santa.daemon.debug.xcconfig */,
E734E4FECEAA502AFF104E71 /* Pods-com.google.santa.daemon.release.xcconfig */,
4A98E2E9727FBEF27CDDA298 /* Pods-syncservice.debug.xcconfig */,
7FEBB0D42E35B93E5B995B06 /* Pods-syncservice.release.xcconfig */,
);
path = Pods;
sourceTree = "<group>";
@@ -924,6 +980,24 @@
productReference = C7F5C1A7233E72BC00A3F7FD /* santabundleservice */;
productType = "com.apple.product-type.tool";
};
C7FA383B24B6136C00D192F9 /* syncservice */ = {
isa = PBXNativeTarget;
buildConfigurationList = C7FA384024B6136C00D192F9 /* Build configuration list for PBXNativeTarget "syncservice" */;
buildPhases = (
20E29BAE9E821A33FE505A22 /* [CP] Check Pods Manifest.lock */,
C7FA383824B6136C00D192F9 /* Sources */,
C7FA383924B6136C00D192F9 /* Frameworks */,
C7FA383A24B6136C00D192F9 /* CopyFiles */,
);
buildRules = (
);
dependencies = (
);
name = syncservice;
productName = syncservice;
productReference = C7FA383C24B6136C00D192F9 /* syncservice */;
productType = "com.apple.product-type.tool";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
@@ -951,6 +1025,9 @@
C7F5C1A6233E72BC00A3F7FD = {
CreatedOnToolsVersion = 11.0;
};
C7FA383B24B6136C00D192F9 = {
CreatedOnToolsVersion = 11.2.1;
};
};
};
buildConfigurationList = C779C2D922F0E95000EE2541 /* Build configuration list for PBXProject "Santa" */;
@@ -972,6 +1049,7 @@
C7658B0B2322B95500F36578 /* santactl */,
C7D35DD92322C902000C5EB4 /* santa-driver */,
C7F5C1A6233E72BC00A3F7FD /* santabundleservice */,
C7FA383B24B6136C00D192F9 /* syncservice */,
);
};
/* End PBXProject section */
@@ -1003,6 +1081,28 @@
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
20E29BAE9E821A33FE505A22 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputFileListPaths = (
);
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-syncservice-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
26354ACD77806EB82836E5A3 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
@@ -1123,6 +1223,7 @@
C7658B522322C1A000F36578 /* SNTCommandSync.m in Sources */,
C7658B452322C17700F36578 /* main.m in Sources */,
C7658B5B2322C2B200F36578 /* SNTConfigurator.m in Sources */,
C7CC459124B618780018C05C /* SNTXPCSyncdInterface.m in Sources */,
C7658B5C2322C2B600F36578 /* SNTDropRootPrivs.m in Sources */,
C7658B582322C1AE00F36578 /* SNTCommandSyncRuleDownload.m in Sources */,
C7658B532322C1A200F36578 /* SNTCommandSyncConstants.m in Sources */,
@@ -1147,7 +1248,6 @@
C7658B502322C19900F36578 /* SNTCommandVersion.m in Sources */,
C7658B482322C18200F36578 /* SNTCommandBundleInfo.m in Sources */,
C7658B612322C2DA00F36578 /* SNTLogging.m in Sources */,
C7658B632322C2E400F36578 /* SNTXPCSyncdInterface.m in Sources */,
C7658B592322C1B000F36578 /* SNTCommandSyncStage.m in Sources */,
C7658B602322C2CB00F36578 /* SNTSystemInfo.m in Sources */,
C7658B552322C1A700F36578 /* SNTCommandSyncManager.m in Sources */,
@@ -1183,8 +1283,8 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
C7CC459224B6188B0018C05C /* SNTXPCSyncdInterface.m in Sources */,
C7658B332322C08B00F36578 /* SNTRule.m in Sources */,
C7658B382322C0B400F36578 /* SNTXPCSyncdInterface.m in Sources */,
C7658B1D2322BFFA00F36578 /* main.m in Sources */,
0D9F577C2342650F005D9AA8 /* SNTPrefixTree.cc in Sources */,
C7658B282322C02300F36578 /* SNTDriverManager.m in Sources */,
@@ -1243,12 +1343,27 @@
C7CDA6FC233E73D80013622B /* SNTFileInfo.m in Sources */,
C7CDA6FF233E80160013622B /* SNTLogging.m in Sources */,
C7CDA6FD233E73E40013622B /* SNTStoredEvent.m in Sources */,
C7FACBFA25646FE500CCB198 /* SNTConfigurator.m in Sources */,
C7CDA6FE233E73ED0013622B /* SNTXPCNotifierInterface.m in Sources */,
C7FACC0225646FEB00CCB198 /* SNTSystemInfo.m in Sources */,
C7F5C1AE233E72CC00A3F7FD /* main.m in Sources */,
C7F5C1AF233E72CF00A3F7FD /* SNTBundleService.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
C7FA383824B6136C00D192F9 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
C7FA384824B6169400D192F9 /* SNTLogging.m in Sources */,
C7FA384924B6169400D192F9 /* SNTStoredEvent.m in Sources */,
C7FA384A24B6169400D192F9 /* SNTXPCSyncServiceInterface.m in Sources */,
C7FA384524B6167800D192F9 /* main.m in Sources */,
C7FA384624B6167800D192F9 /* SNTSyncService.h in Sources */,
C7FA384724B6167800D192F9 /* SNTSyncService.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin XCBuildConfiguration section */
@@ -1256,7 +1371,7 @@
isa = XCBuildConfiguration;
baseConfigurationReference = 052CCA75535669B953A31D6D /* Pods-santactl.debug.xcconfig */;
buildSettings = {
CODE_SIGN_IDENTITY = "Mac Developer";
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Manual;
CREATE_INFOPLIST_SECTION_IN_BINARY = YES;
CURRENT_PROJECT_VERSION = 1;
@@ -1274,7 +1389,7 @@
isa = XCBuildConfiguration;
baseConfigurationReference = 0A60226B8B4F01BE817BAAA3 /* Pods-santactl.release.xcconfig */;
buildSettings = {
CODE_SIGN_IDENTITY = "Mac Developer";
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Manual;
CREATE_INFOPLIST_SECTION_IN_BINARY = YES;
CURRENT_PROJECT_VERSION = 1;
@@ -1342,7 +1457,6 @@
MACOSX_DEPLOYMENT_TARGET = 10.11;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = macosx;
};
name = Debug;
@@ -1405,7 +1519,7 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_ENTITLEMENTS = Source/santa/Santa.app.entitlements;
CODE_SIGN_IDENTITY = "Mac Developer";
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Manual;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 1;
@@ -1429,7 +1543,7 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_ENTITLEMENTS = Source/santa/Santa.app.entitlements;
CODE_SIGN_IDENTITY = "Mac Developer";
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Manual;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 1;
@@ -1452,7 +1566,7 @@
baseConfigurationReference = 4E28DBA012524ABF55F8300C /* Pods-com.google.santa.daemon.debug.xcconfig */;
buildSettings = {
CODE_SIGN_ENTITLEMENTS = Source/santad/com.google.santa.daemon.systemextension.entitlements;
CODE_SIGN_IDENTITY = "Mac Developer";
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Manual;
CREATE_INFOPLIST_SECTION_IN_BINARY = YES;
CURRENT_PROJECT_VERSION = 1;
@@ -1471,7 +1585,7 @@
baseConfigurationReference = E734E4FECEAA502AFF104E71 /* Pods-com.google.santa.daemon.release.xcconfig */;
buildSettings = {
CODE_SIGN_ENTITLEMENTS = Source/santad/com.google.santa.daemon.systemextension.entitlements;
CODE_SIGN_IDENTITY = "Mac Developer";
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Manual;
CREATE_INFOPLIST_SECTION_IN_BINARY = YES;
CURRENT_PROJECT_VERSION = 1;
@@ -1490,7 +1604,7 @@
baseConfigurationReference = D7360306D7CFDD179D003266 /* Pods-sysx.debug.xcconfig */;
buildSettings = {
CODE_SIGN_ENTITLEMENTS = Source/santad/com.google.santa.daemon.systemextension.entitlements;
CODE_SIGN_IDENTITY = "Mac Developer";
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Manual;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 1;
@@ -1511,7 +1625,7 @@
baseConfigurationReference = C05543B3701F50CA798B4B11 /* Pods-sysx.release.xcconfig */;
buildSettings = {
CODE_SIGN_ENTITLEMENTS = Source/santad/com.google.santa.daemon.systemextension.entitlements;
CODE_SIGN_IDENTITY = "Mac Developer";
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Manual;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 1;
@@ -1530,7 +1644,7 @@
C7D35DE02322C902000C5EB4 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_IDENTITY = "Mac Developer";
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = EQHXZ8M8AV;
@@ -1550,7 +1664,7 @@
C7D35DE12322C902000C5EB4 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_IDENTITY = "Mac Developer";
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = EQHXZ8M8AV;
@@ -1571,7 +1685,7 @@
isa = XCBuildConfiguration;
baseConfigurationReference = D4808D8635FB5E8E5F4637BB /* Pods-santabundleservice.debug.xcconfig */;
buildSettings = {
CODE_SIGN_IDENTITY = "Mac Developer";
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Manual;
CREATE_INFOPLIST_SECTION_IN_BINARY = YES;
DEVELOPMENT_TEAM = EQHXZ8M8AV;
@@ -1586,7 +1700,7 @@
isa = XCBuildConfiguration;
baseConfigurationReference = FE1F7C320CAEA468FAAC05B0 /* Pods-santabundleservice.release.xcconfig */;
buildSettings = {
CODE_SIGN_IDENTITY = "Mac Developer";
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Manual;
CREATE_INFOPLIST_SECTION_IN_BINARY = YES;
DEVELOPMENT_TEAM = EQHXZ8M8AV;
@@ -1597,6 +1711,32 @@
};
name = Release;
};
C7FA384124B6136C00D192F9 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 4A98E2E9727FBEF27CDDA298 /* Pods-syncservice.debug.xcconfig */;
buildSettings = {
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Manual;
DEVELOPMENT_TEAM = EQHXZ8M8AV;
ENABLE_HARDENED_RUNTIME = YES;
MACOSX_DEPLOYMENT_TARGET = 10.15;
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Debug;
};
C7FA384224B6136C00D192F9 /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7FEBB0D42E35B93E5B995B06 /* Pods-syncservice.release.xcconfig */;
buildSettings = {
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Manual;
DEVELOPMENT_TEAM = EQHXZ8M8AV;
ENABLE_HARDENED_RUNTIME = YES;
MACOSX_DEPLOYMENT_TARGET = 10.15;
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
@@ -1663,6 +1803,15 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
C7FA384024B6136C00D192F9 /* Build configuration list for PBXNativeTarget "syncservice" */ = {
isa = XCConfigurationList;
buildConfigurations = (
C7FA384124B6136C00D192F9 /* Debug */,
C7FA384224B6136C00D192F9 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = C779C2D622F0E95000EE2541 /* Project object */;

View File

@@ -1,8 +1,23 @@
package(default_visibility = ["//visibility:public"])
load("//:helper.bzl", "santa_unit_test")
package(default_visibility = ["//:santa_package_group"])
licenses(["notice"]) # Apache 2.0
load("//:helper.bzl", "santa_unit_test")
cc_library(
name = "SantaCache",
srcs = ["SantaCache.h"],
deps = ["//Source/common:SNTKernelCommon"],
)
santa_unit_test(
name = "SantaCacheTest",
srcs = [
"SantaCache.h",
"SantaCacheTest.mm",
],
deps = ["//Source/common:SNTKernelCommon"],
)
objc_library(
name = "SNTBlockMessage",
@@ -10,6 +25,7 @@ objc_library(
hdrs = ["SNTBlockMessage.h"],
deps = [
":SNTConfigurator",
":SNTLogging",
":SNTStoredEvent",
],
)
@@ -21,6 +37,7 @@ objc_library(
defines = ["SANTAGUI"],
deps = [
":SNTConfigurator",
":SNTLogging",
":SNTStoredEvent",
],
)
@@ -35,7 +52,7 @@ objc_library(
],
)
cc_library(
objc_library(
name = "SNTCommonEnums",
hdrs = ["SNTCommonEnums.h"],
)
@@ -46,7 +63,6 @@ objc_library(
hdrs = ["SNTConfigurator.h"],
deps = [
":SNTCommonEnums",
":SNTLogging",
":SNTStrengthify",
":SNTSystemInfo",
],
@@ -76,12 +92,18 @@ cc_library(
cc_library(
name = "SNTLoggingKernel",
hdrs = ["SNTLogging.h"],
copts = [
"-mkernel",
"-I__BAZEL_XCODE_SDKROOT__/System/Library/Frameworks/Kernel.framework/Headers",
],
defines = ["KERNEL"],
)
objc_library(
name = "SNTLogging",
srcs = ["SNTLogging.m"],
hdrs = ["SNTLogging.h"],
deps = [":SNTConfigurator"],
)
cc_library(
@@ -176,6 +198,16 @@ objc_library(
],
)
objc_library(
name = "SNTXPCSyncServiceInterface",
srcs = ["SNTXPCSyncServiceInterface.m"],
hdrs = ["SNTXPCSyncServiceInterface.h"],
deps = [
":SNTStoredEvent",
"@MOLXPCConnection",
],
)
objc_library(
name = "SNTXPCUnprivilegedControlInterface",
srcs = ["SNTXPCUnprivilegedControlInterface.m"],
@@ -197,6 +229,7 @@ santa_unit_test(
resources = [
"testdata/bad_pagezero",
"testdata/missing_pagezero",
"testdata/32bitplist",
],
structured_resources = glob([
"testdata/BundleExample.app/**",

View File

@@ -17,6 +17,7 @@
#import "Source/common/SNTConfigurator.h"
#import "Source/common/SNTLogging.h"
#import "Source/common/SNTStoredEvent.h"
#import "Source/common/SNTSystemInfo.h"
@implementation SNTBlockMessage
@@ -106,6 +107,9 @@
+ (NSURL *)eventDetailURLForEvent:(SNTStoredEvent *)event {
SNTConfigurator *config = [SNTConfigurator configurator];
NSString *hostname = [SNTSystemInfo longHostname];
NSString *uuid = [SNTSystemInfo hardwareUUID];
NSString *serial = [SNTSystemInfo serialNumber];
NSString *formatStr = config.eventDetailURL;
if (!formatStr.length) return nil;
@@ -122,6 +126,15 @@
formatStr = [formatStr stringByReplacingOccurrencesOfString:@"%machine_id%"
withString:config.machineID];
}
if (hostname.length) {
formatStr = [formatStr stringByReplacingOccurrencesOfString:@"%hostname%" withString:hostname];
}
if (uuid.length) {
formatStr = [formatStr stringByReplacingOccurrencesOfString:@"%uuid%" withString:uuid];
}
if (serial.length) {
formatStr = [formatStr stringByReplacingOccurrencesOfString:@"%serial%" withString:serial];
}
return [NSURL URLWithString:formatStr];
}

View File

@@ -29,13 +29,13 @@ typedef NS_ENUM(NSInteger, SNTRuleType) {
typedef NS_ENUM(NSInteger, SNTRuleState) {
SNTRuleStateUnknown,
SNTRuleStateWhitelist = 1,
SNTRuleStateBlacklist = 2,
SNTRuleStateSilentBlacklist = 3,
SNTRuleStateAllow = 1,
SNTRuleStateBlock = 2,
SNTRuleStateSilentBlock = 3,
SNTRuleStateRemove = 4,
SNTRuleStateWhitelistCompiler = 5,
SNTRuleStateWhitelistTransitive = 6,
SNTRuleStateAllowCompiler = 5,
SNTRuleStateAllowTransitive = 6,
};
typedef NS_ENUM(NSInteger, SNTClientMode) {

View File

@@ -36,32 +36,32 @@
- (void)setSyncServerClientMode:(SNTClientMode)newMode;
///
/// The regex of whitelisted paths. Regexes are specified in ICU format.
/// The regex of allowed paths. Regexes are specified in ICU format.
///
/// The regex flags IXSM can be used, though the s (dotall) and m (multiline) flags are
/// pointless as a path only ever has a single line.
/// If the regex doesn't begin with ^ to match from the beginning of the line, it will be added.
///
@property(readonly, nonatomic) NSRegularExpression *whitelistPathRegex;
@property(readonly, nonatomic) NSRegularExpression *allowedPathRegex;
///
/// Set the regex of whitelisted paths as received from a sync server.
/// Set the regex of allowed paths as received from a sync server.
///
- (void)setSyncServerWhitelistPathRegex:(NSRegularExpression *)re;
- (void)setSyncServerAllowedPathRegex:(NSRegularExpression *)re;
///
/// The regex of blacklisted paths. Regexes are specified in ICU format.
/// The regex of blocked paths. Regexes are specified in ICU format.
///
/// The regex flags IXSM can be used, though the s (dotall) and m (multiline) flags are
/// pointless as a path only ever has a single line.
/// If the regex doesn't begin with ^ to match from the beginning of the line, it will be added.
///
@property(readonly, nonatomic) NSRegularExpression *blacklistPathRegex;
@property(readonly, nonatomic) NSRegularExpression *blockedPathRegex;
///
/// Set the regex of blacklisted paths as received from a sync server.
/// Set the regex of blocked paths as received from a sync server.
///
- (void)setSyncServerBlacklistPathRegex:(NSRegularExpression *)re;
- (void)setSyncServerBlockedPathRegex:(NSRegularExpression *)re;
///
/// The regex of paths to log file changes for. Regexes are specified in ICU format.
@@ -133,7 +133,7 @@
///
/// Enable bad signature protection, defaults to NO.
/// When enabled, a binary that is signed but has a bad signature (cert revoked, binary
/// tampered with, etc.) will be blocked regardless of client-mode unless a binary whitelist
/// tampered with, etc.) will be blocked regardless of client-mode unless a binary allowlist
/// rule exists.
///
@property(readonly, nonatomic) BOOL enableBadSignatureProtection;
@@ -173,6 +173,15 @@
///
@property(readonly, nonatomic) BOOL enableSystemExtension;
///
/// Use an internal cache for decisions instead of relying on the caching
/// mechanism built-in to the EndpointSecurity framework. This may increase
/// performance, particularly when Santa is run alongside other system
/// extensions.
/// Has no effect if the system extension is not being used. Defaults to NO.
///
@property(readonly, nonatomic) BOOL enableSysxCache;
#pragma mark - GUI Settings
///
@@ -191,6 +200,9 @@
/// %file_sha% -- SHA-256 of the file that was blocked.
/// %machine_id% -- ID of the machine.
/// %username% -- executing user.
/// %serial% -- System's serial number.
/// %uuid% -- System's UUID.
/// %hostname% -- System's full hostname.
///
/// @note: This is not an NSURL because the format-string parsing is done elsewhere.
///
@@ -266,14 +278,14 @@
///
@property BOOL enableBundles;
#pragma mark Transitive Whitelisting Settings
#pragma mark Transitive Allowlist Settings
///
/// If YES, binaries marked with SNTRuleStateWhitelistCompiler rules are allowed to transitively
/// whitelist any executables that they produce. If NO, SNTRuleStateWhitelistCompiler rules are
/// interpreted as if they were simply SNTRuleStateWhitelist rules. Defaults to NO.
/// If YES, binaries marked with SNTRuleStateAllowCompiler rules are allowed to transitively
/// allow any executables that they produce. If NO, SNTRuleStateAllowCompiler rules are
/// interpreted as if they were simply SNTRuleStateAllow rules. Defaults to NO.
///
@property BOOL enableTransitiveWhitelisting;
@property BOOL enableTransitiveRules;
#pragma mark Server Auth Settings
@@ -312,6 +324,31 @@
///
@property(readonly, nonatomic) NSString *syncClientAuthCertificateIssuer;
///
/// If true, forks and exits will be logged. Defaults to false.
///
@property(readonly, nonatomic) BOOL enableForkAndExitLogging;
///
/// If true, ignore actions from other endpoint security clients. Defaults to false. This only
/// applies when running as a sysx.
///
@property(readonly, nonatomic) BOOL ignoreOtherEndpointSecurityClients;
///
/// If true, debug logging will be enabled for all Santa components. Defaults to false.
/// Passing --debug as an executable argument will enable debug logging for that specific component.
///
@property(readonly, nonatomic) BOOL enableDebugLogging;
///
/// If true, compressed requests from "santactl sync" will set "Content-Encoding" to "zlib"
/// instead of the new default "deflate". If syncing with Upvote deployed at commit 0b4477d
/// or below, set this option to true.
/// Defaults to false.
///
@property(readonly, nonatomic) BOOL enableBackwardsCompatibleContentEncoding;
///
/// Retrieve an initialized singleton configurator object using the default file path.
///

View File

@@ -16,7 +16,6 @@
#include <sys/stat.h>
#import "Source/common/SNTLogging.h"
#import "Source/common/SNTStrengthify.h"
#import "Source/common/SNTSystemInfo.h"
@@ -24,13 +23,16 @@
/// A NSUserDefaults object set to use the com.google.santa suite.
@property(readonly, nonatomic) NSUserDefaults *defaults;
// Keys and expected value types.
/// Keys and expected value types.
@property(readonly, nonatomic) NSDictionary *syncServerKeyTypes;
@property(readonly, nonatomic) NSDictionary *forcedConfigKeyTypes;
/// Holds the configurations from a sync server and mobileconfig.
@property NSMutableDictionary *syncState;
@property NSMutableDictionary *configState;
/// Was --debug passed as an argument to this process?
@property(readonly, nonatomic) BOOL debugFlag;
@end
@implementation SNTConfigurator
@@ -77,12 +79,22 @@ static NSString *const kEventLogPath = @"EventLogPath";
static NSString *const kEnableMachineIDDecoration = @"EnableMachineIDDecoration";
static NSString *const kEnableSystemExtension = @"EnableSystemExtension";
static NSString *const kEnableSysxCache = @"EnableSysxCache";
static NSString *const kEnableForkAndExitLogging = @"EnableForkAndExitLogging";
static NSString *const kIgnoreOtherEndpointSecurityClients = @"IgnoreOtherEndpointSecurityClients";
static NSString *const kEnableDebugLogging = @"EnableDebugLogging";
static NSString *const kEnableBackwardsCompatibleContentEncoding = @"EnableBackwardsCompatibleContentEncoding";
// The keys managed by a sync server or mobileconfig.
static NSString *const kClientModeKey = @"ClientMode";
static NSString *const kEnableTransitiveWhitelistingKey = @"EnableTransitiveWhitelisting";
static NSString *const kWhitelistRegexKey = @"WhitelistRegex";
static NSString *const kBlacklistRegexKey = @"BlacklistRegex";
static NSString *const kEnableTransitiveRulesKey = @"EnableTransitiveRules";
static NSString *const kEnableTransitiveRulesKeyDeprecated = @"EnableTransitiveWhitelisting";
static NSString *const kAllowedPathRegexKey = @"AllowedPathRegex";
static NSString *const kAllowedPathRegexKeyDeprecated = @"WhitelistRegex";
static NSString *const kBlockedPathRegexKey = @"BlockedPathRegex";
static NSString *const kBlockedPathRegexKeyDeprecated = @"BlacklistRegex";
// The keys managed by a sync server.
static NSString *const kFullSyncLastSuccess = @"FullSyncLastSuccess";
@@ -100,22 +112,28 @@ static NSString *const kSyncCleanRequired = @"SyncCleanRequired";
Class array = [NSArray class];
_syncServerKeyTypes = @{
kClientModeKey : number,
kEnableTransitiveWhitelistingKey : number,
kWhitelistRegexKey : re,
kBlacklistRegexKey : re,
kEnableTransitiveRulesKey : number,
kEnableTransitiveRulesKeyDeprecated : number,
kAllowedPathRegexKey : re,
kAllowedPathRegexKeyDeprecated : re,
kBlockedPathRegexKey : re,
kBlockedPathRegexKeyDeprecated : re,
kFullSyncLastSuccess : date,
kRuleSyncLastSuccess : date,
kSyncCleanRequired : number
};
_forcedConfigKeyTypes = @{
kClientModeKey : number,
kEnableTransitiveWhitelistingKey : number,
kEnableTransitiveRulesKey : number,
kEnableTransitiveRulesKeyDeprecated : number,
kFileChangesRegexKey : re,
kFileChangesPrefixFiltersKey : array,
kWhitelistRegexKey : re,
kBlacklistRegexKey : re,
kAllowedPathRegexKey : re,
kAllowedPathRegexKeyDeprecated : re,
kBlockedPathRegexKey : re,
kBlockedPathRegexKeyDeprecated : re,
kEnablePageZeroProtectionKey : number,
kEnableBadSignatureProtectionKey: number,
kEnableBadSignatureProtectionKey : number,
kMoreInfoURLKey : string,
kEventDetailURLKey : string,
kEventDetailTextKey : string,
@@ -128,7 +146,7 @@ static NSString *const kSyncCleanRequired = @"SyncCleanRequired";
kClientAuthCertificatePasswordKey : string,
kClientAuthCertificateCNKey : string,
kClientAuthCertificateIssuerKey : string,
kServerAuthRootsDataKey : data,
kServerAuthRootsDataKey : data,
kServerAuthRootsFileKey : string,
kMachineOwnerKey : string,
kMachineIDKey : string,
@@ -140,11 +158,17 @@ static NSString *const kSyncCleanRequired = @"SyncCleanRequired";
kEventLogPath : string,
kEnableMachineIDDecoration : number,
kEnableSystemExtension : number,
kEnableSysxCache : number,
kEnableForkAndExitLogging : number,
kIgnoreOtherEndpointSecurityClients : number,
kEnableDebugLogging : number,
kEnableBackwardsCompatibleContentEncoding : number,
};
_defaults = [NSUserDefaults standardUserDefaults];
[_defaults addSuiteNamed:@"com.google.santa"];
_configState = [self readForcedConfig];
_syncState = [self readSyncStateFromDisk] ?: [NSMutableDictionary dictionary];
_debugFlag = [[NSProcessInfo processInfo].arguments containsObject:@"--debug"];
[self startWatchingDefaults];
}
return self;
@@ -194,11 +218,11 @@ static NSString *const kSyncCleanRequired = @"SyncCleanRequired";
return [self syncAndConfigStateSet];
}
+ (NSSet *)keyPathsForValuesAffectingWhitelistPathRegex {
+ (NSSet *)keyPathsForValuesAffectingAllowlistPathRegex {
return [self syncAndConfigStateSet];
}
+ (NSSet *)keyPathsForValuesAffectingBlacklistPathRegex {
+ (NSSet *)keyPathsForValuesAffectingBlocklistPathRegex {
return [self syncAndConfigStateSet];
}
@@ -302,7 +326,7 @@ static NSString *const kSyncCleanRequired = @"SyncCleanRequired";
return [self configStateSet];
}
+ (NSSet *)keyPathsForValuesAffectingEnableTransitiveWhitelisting {
+ (NSSet *)keyPathsForValuesAffectingEnableTransitiveRules {
return [self syncAndConfigStateSet];
}
@@ -310,6 +334,26 @@ static NSString *const kSyncCleanRequired = @"SyncCleanRequired";
return [self configStateSet];
}
+ (NSSet *)keyPathsForValuesAffectingEnableSysxCache {
return [self configStateSet];
}
+ (NSSet *)keyPathsForValuesAffectingEnableForkAndExitLogging {
return [self configStateSet];
}
+ (NSSet *)keyPathsForValuesAffectingIgnoreOtherEndpointSecurityClients {
return [self configStateSet];
}
+ (NSSet *)keyPathsForValuesAffectingEnableDebugLogging {
return [self configStateSet];
}
+ (NSSet *)keyPathsForValuesAffectingEnableBackwardsCompatibleContentEncoding {
return [self configStateSet];
}
#pragma mark Public Interface
- (SNTClientMode)clientMode {
@@ -329,37 +373,58 @@ static NSString *const kSyncCleanRequired = @"SyncCleanRequired";
- (void)setSyncServerClientMode:(SNTClientMode)newMode {
if (newMode == SNTClientModeMonitor || newMode == SNTClientModeLockdown) {
[self updateSyncStateForKey:kClientModeKey value:@(newMode)];
} else {
LOGW(@"Ignoring request to change client mode to %ld", newMode);
}
}
- (BOOL)enableTransitiveWhitelisting {
NSNumber *n = self.syncState[kEnableTransitiveWhitelistingKey];
if (n) {
return [n boolValue];
}
return [self.configState[kEnableTransitiveWhitelistingKey] boolValue];
- (BOOL)enableTransitiveRules {
NSNumber *n = self.syncState[kEnableTransitiveRulesKey];
if (n) return [n boolValue];
n = self.syncState[kEnableTransitiveRulesKeyDeprecated];
if (n) return [n boolValue];
n = self.configState[kEnableTransitiveRulesKeyDeprecated];
if (n) return [n boolValue];
return [self.configState[kEnableTransitiveRulesKey] boolValue];
}
- (void)setEnableTransitiveWhitelisting:(BOOL)enabled {
[self updateSyncStateForKey:kEnableTransitiveWhitelistingKey value:@(enabled)];
- (void)setEnableTransitiveRules:(BOOL)enabled {
[self updateSyncStateForKey:kEnableTransitiveRulesKey value:@(enabled)];
}
- (NSRegularExpression *)whitelistPathRegex {
return self.syncState[kWhitelistRegexKey] ?: self.configState[kWhitelistRegexKey];
- (NSRegularExpression *)allowedPathRegex {
NSRegularExpression *r = self.syncState[kAllowedPathRegexKey];
if (r) return r;
r = self.syncState[kAllowedPathRegexKeyDeprecated];
if (r) return r;
r = self.configState[kAllowedPathRegexKey];
if (r) return r;
return self.configState[kAllowedPathRegexKeyDeprecated];
}
- (void)setSyncServerWhitelistPathRegex:(NSRegularExpression *)re {
[self updateSyncStateForKey:kWhitelistRegexKey value:re];
- (void)setSyncServerAllowedPathRegex:(NSRegularExpression *)re {
[self updateSyncStateForKey:kAllowedPathRegexKey value:re];
}
- (NSRegularExpression *)blacklistPathRegex {
return self.syncState[kBlacklistRegexKey] ?: self.configState[kBlacklistRegexKey];
- (NSRegularExpression *)blockedPathRegex {
NSRegularExpression *r = self.syncState[kBlockedPathRegexKey];
if (r) return r;
r = self.syncState[kBlockedPathRegexKeyDeprecated];
if (r) return r;
r = self.configState[kBlockedPathRegexKey];
if (r) return r;
return self.configState[kBlockedPathRegexKeyDeprecated];
}
- (void)setSyncServerBlacklistPathRegex:(NSRegularExpression *)re {
[self updateSyncStateForKey:kBlacklistRegexKey value:re];
- (void)setSyncServerBlockedPathRegex:(NSRegularExpression *)re {
[self updateSyncStateForKey:kBlockedPathRegexKey value:re];
}
- (NSRegularExpression *)fileChangesRegex {
@@ -370,7 +435,6 @@ static NSString *const kSyncCleanRequired = @"SyncCleanRequired";
NSArray *filters = self.configState[kFileChangesPrefixFiltersKey];
for (id filter in filters) {
if (![filter isKindOfClass:[NSString class]]) {
LOGE(@"Ignoring FileChangesPrefixFilters: array contains a non-string %@", filter);
return nil;
}
}
@@ -381,7 +445,6 @@ static NSString *const kSyncCleanRequired = @"SyncCleanRequired";
NSString *urlString = self.configState[kSyncBaseURLKey];
if (![urlString hasSuffix:@"/"]) urlString = [urlString stringByAppendingString:@"/"];
NSURL *url = [NSURL URLWithString:urlString];
if (urlString && !url) LOGW(@"SyncBaseURL is not a valid URL!");
return url;
}
@@ -526,6 +589,31 @@ static NSString *const kSyncCleanRequired = @"SyncCleanRequired";
}
}
- (BOOL)enableSysxCache {
NSNumber *number = self.configState[kEnableSysxCache];
return number ? [number boolValue] : NO;
}
- (BOOL)enableForkAndExitLogging {
NSNumber *number = self.configState[kEnableForkAndExitLogging];
return number ? [number boolValue] : NO;
}
- (BOOL)ignoreOtherEndpointSecurityClients {
NSNumber *number = self.configState[kIgnoreOtherEndpointSecurityClients];
return number ? [number boolValue] : NO;
}
- (BOOL)enableDebugLogging {
NSNumber *number = self.configState[kEnableDebugLogging];
return [number boolValue] || self.debugFlag;
}
- (BOOL)enableBackwardsCompatibleContentEncoding {
NSNumber *number = self.configState[kEnableBackwardsCompatibleContentEncoding];
return number ? [number boolValue] : NO;
}
#pragma mark Private
///
@@ -572,8 +660,8 @@ static NSString *const kSyncCleanRequired = @"SyncCleanRequired";
if (geteuid() != 0) return;
// Either remove
NSMutableDictionary *syncState = self.syncState.mutableCopy;
syncState[kWhitelistRegexKey] = [syncState[kWhitelistRegexKey] pattern];
syncState[kBlacklistRegexKey] = [syncState[kBlacklistRegexKey] pattern];
syncState[kAllowedPathRegexKey] = [syncState[kAllowedPathRegexKey] pattern];
syncState[kBlockedPathRegexKey] = [syncState[kBlockedPathRegexKey] pattern];
[syncState writeToFile:kSyncStateFilePath atomically:YES];
[[NSFileManager defaultManager] setAttributes:@{ NSFilePosixPermissions : @0644 }
ofItemAtPath:kSyncStateFilePath error:NULL];
@@ -611,8 +699,9 @@ static NSString *const kSyncCleanRequired = @"SyncCleanRequired";
}
- (void)startWatchingDefaults {
// Only santad should listen.
if (geteuid() != 0) return;
// Only com.google.santa.daemon should listen.
NSString *processName = [[NSProcessInfo processInfo] processName];
if (![processName isEqualToString:@"com.google.santa.daemon"]) return;
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(defaultsChanged:)
name:NSUserDefaultsDidChangeNotification

View File

@@ -551,24 +551,51 @@ extern NSString *const NSURLQuarantinePropertiesKey WEAK_IMPORT_ATTRIBUTE;
for (uint32_t i = 0; i < ncmds; ++i) {
NSData *cmdData = [self safeSubdataWithRange:NSMakeRange(offset, sz_segment)];
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 (memcmp(lc->segname, "__TEXT", 6) == 0) {
if (is64) {
struct segment_command_64 *lc = (struct segment_command_64 *)[cmdData bytes];
if (lc->cmd == LC_SEGMENT_64 && memcmp(lc->segname, "__TEXT", 6) == 0) {
nsects = lc->nsects;
offset += sz_segment;
break;
}
offset += lc->cmdsize;
} else {
struct segment_command *lc = (struct segment_command *)[cmdData bytes];
if (lc->cmd == LC_SEGMENT && memcmp(lc->segname, "__TEXT", 6) == 0) {
nsects = lc->nsects;
offset += sz_segment;
break;
}
offset += lc->cmdsize;
}
offset += lc->cmdsize;
}
// Loop through the sections in the __TEXT segment looking for an __info_plist section.
for (uint32_t i = 0; i < nsects; ++i) {
NSData *sectData = [self safeSubdataWithRange:NSMakeRange(offset, sz_section)];
if (!sectData) return nil;
struct section_64 *sect = (struct section_64 *)[sectData bytes];
if (sect && memcmp(sect->sectname, "__info_plist", 12) == 0 && sect->size < 2000000) {
NSData *plistData = [self safeSubdataWithRange:NSMakeRange(sect->offset, sect->size)];
uint64_t sectoffset, sectsize = 0;
BOOL found = NO;
if (is64) {
struct section_64 *sect = (struct section_64 *)[sectData bytes];
if (sect && memcmp(sect->sectname, "__info_plist", 12) == 0 && sect->size < 2000000) {
sectoffset = sect->offset;
sectsize = sect->size;
found = YES;
}
} else {
struct section *sect = (struct section *)[sectData bytes];
if (sect && memcmp(sect->sectname, "__info_plist", 12) == 0 && sect->size < 2000000) {
sectoffset = sect->offset;
sectsize = sect->size;
found = YES;
}
}
if (found) {
NSData *plistData = [self safeSubdataWithRange:NSMakeRange(mhwo.offset + sectoffset,
sectsize)];
if (!plistData) return nil;
NSDictionary *plist;
plist = [NSPropertyListSerialization propertyListWithData:plistData

View File

@@ -39,9 +39,8 @@
sut = [[SNTFileInfo alloc] initWithPath:@"../../../../../../../../../../../../../../../bin/ls"];
XCTAssertEqualObjects(sut.path, @"/bin/ls");
sut = [[SNTFileInfo alloc] initWithPath:@"/usr/sbin/AppleFileServer"];
XCTAssertEqualObjects(sut.path, @"/System/Library/CoreServices/AppleFileServer.app/"
@"Contents/MacOS/AppleFileServer");
sut = [[SNTFileInfo alloc] initWithPath:@"/usr/sbin/DirectoryService"];
XCTAssertEqualObjects(sut.path, @"/usr/libexec/dspluginhelperd");
}
- (void)testSHA1 {
@@ -72,7 +71,6 @@
XCTAssertTrue(sut.isExecutable);
XCTAssertFalse(sut.isDylib);
XCTAssertFalse(sut.isFat);
XCTAssertFalse(sut.isKext);
XCTAssertFalse(sut.isScript);
}
@@ -106,7 +104,7 @@
}
- (void)testDylibs {
SNTFileInfo *sut = [[SNTFileInfo alloc] initWithPath:@"/usr/lib/libsqlite3.dylib"];
SNTFileInfo *sut = [[SNTFileInfo alloc] initWithPath:@"/usr/lib/system/libsystem_platform.dylib"];
XCTAssertTrue(sut.isMachO);
XCTAssertTrue(sut.isDylib);
@@ -231,10 +229,16 @@
}
- (void)testEmbeddedInfoPlist {
NSString *path = [[NSBundle bundleForClass:[self class]] pathForResource:@"32bitplist"
ofType:@""];
SNTFileInfo *sut = [[SNTFileInfo alloc] initWithPath:path];
XCTAssertNotNil([sut infoPlist]);
XCTAssertEqualObjects([sut infoPlist][@"CFBundleShortVersionString"], @"1.0");
XCTAssertEqualObjects([sut infoPlist][@"CFBundleIdentifier"], @"com.google.i386plist");
// csreq is installed on all machines with Xcode installed. If you're running these tests,
// it should be available..
SNTFileInfo *sut = [[SNTFileInfo alloc] initWithPath:@"/usr/bin/csreq"];
sut = [[SNTFileInfo alloc] initWithPath:@"/usr/bin/csreq"];
XCTAssertNotNil([sut infoPlist]);
}

View File

@@ -16,11 +16,12 @@
/// Common defines between kernel <-> userspace
///
#include <sys/param.h>
#ifndef SANTA__COMMON__KERNELCOMMON_H
#define SANTA__COMMON__KERNELCOMMON_H
#include <stdint.h>
#include <sys/param.h>
// Defines the name of the userclient class and the driver bundle ID.
#define USERCLIENT_CLASS "com_google_SantaDriver"
#define USERCLIENT_ID "com.google.santa-driver"
@@ -81,6 +82,8 @@ typedef enum {
ACTION_NOTIFY_EXCHANGE = 34,
ACTION_NOTIFY_DELETE = 35,
ACTION_NOTIFY_WHITELIST = 36,
ACTION_NOTIFY_FORK = 37,
ACTION_NOTIFY_EXIT = 38,
// ERROR
ACTION_ERROR = 99,
@@ -116,6 +119,7 @@ typedef struct {
uid_t uid;
gid_t gid;
pid_t pid;
int pidversion;
pid_t ppid;
char path[MAXPATHLEN];
char newpath[MAXPATHLEN];

View File

@@ -14,6 +14,8 @@
#import "Source/common/SNTLogging.h"
#import "Source/common/SNTConfigurator.h"
#import <asl.h>
#import <pthread.h>
@@ -39,8 +41,7 @@ void logMessage(LogLevel level, FILE *destination, NSString *format, ...) {
dispatch_once(&pred, ^{
binaryName = [[NSProcessInfo processInfo] processName];
// If debug logging is enabled, the process must be restarted.
if ([[[NSProcessInfo processInfo] arguments] containsObject:@"--debug"]) {
if ([SNTConfigurator configurator].enableDebugLogging) {
logLevel = LOG_LEVEL_DEBUG;
}

View File

@@ -92,9 +92,6 @@ class SNTPrefixTree {
lck_rw_t *spt_lock_;
lck_mtx_t *spt_add_lock_;
#else // KERNEL
void *spt_lock_grp_;
void *spt_lock_grp_attr_;
void *spt_lock_attr_;
pthread_rwlock_t spt_lock_;
std::mutex *spt_add_lock_;
#endif // KERNEL

View File

@@ -46,7 +46,7 @@
customMsg:customMsg
timestamp:0];
// Initialize timestamp to current time if rule is transitive.
if (self && state == SNTRuleStateWhitelistTransitive) {
if (self && state == SNTRuleStateAllowTransitive) {
[self resetTimestamp];
}
return self;

View File

@@ -44,10 +44,10 @@
- (void)setFullSyncLastSuccess:(NSDate *)date reply:(void (^)(void))reply;
- (void)setRuleSyncLastSuccess:(NSDate *)date reply:(void (^)(void))reply;
- (void)setSyncCleanRequired:(BOOL)cleanReqd reply:(void (^)(void))reply;
- (void)setWhitelistPathRegex:(NSString *)pattern reply:(void (^)(void))reply;
- (void)setBlacklistPathRegex:(NSString *)pattern reply:(void (^)(void))reply;
- (void)setAllowedPathRegex:(NSString *)pattern reply:(void (^)(void))reply;
- (void)setBlockedPathRegex:(NSString *)pattern reply:(void (^)(void))reply;
- (void)setEnableBundles:(BOOL)bundlesEnabled reply:(void (^)(void))reply;
- (void)setEnableTransitiveWhitelisting:(BOOL)enabled reply:(void (^)(void))reply;
- (void)setEnableTransitiveRules:(BOOL)enabled reply:(void (^)(void))reply;
///
/// Syncd Ops

View File

@@ -0,0 +1,56 @@
/// Copyright 2020 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 <Foundation/Foundation.h>
#import <MOLXPCConnection/MOLXPCConnection.h>
#import "Source/common/SNTCommonEnums.h"
@class SNTStoredEvent;
/// A block that reports the number of rules processed.
/// TODO(bur): Add more details about the sync.
typedef void (^SNTFullSyncReplyBlock)(NSNumber *rulesProcessed);
/// Protocol implemented by syncservice and utilized by daemon and ctl for communication with a sync server.
@protocol SNTSyncServiceXPC
- (void)postEventsToSyncServer:(NSArray<SNTStoredEvent *> *)events fromBundle:(BOOL)fromBundle;
- (void)postBundleEventToSyncServer:(SNTStoredEvent *)event
reply:(void (^)(SNTBundleEventAction))reply;
- (void)isFCMListening:(void (^)(BOOL))reply;
- (void)performFullSyncWithReply:(SNTFullSyncReplyBlock)reply;
@end
@interface SNTXPCSyncServiceInterface : NSObject
///
/// Returns an initialized NSXPCInterface for the SNTSyncServiceXPC protocol.
/// Ensures any methods that accept custom classes as arguments are set-up before returning.
///
+ (NSXPCInterface *)syncServiceInterface;
///
/// Returns the MachService ID for this service.
///
+ (NSString *)serviceID;
///
/// Retrieve a pre-configured MOLXPCConnection for communicating with syncservice.
/// Connections just needs any handlers set and then can be resumed and used.
///
+ (MOLXPCConnection *)configuredConnection;
@end

View File

@@ -0,0 +1,43 @@
/// Copyright 2020 Google Inc. All rights reserved.
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
#import "Source/common/SNTXPCSyncServiceInterface.h"
#import "Source/common/SNTStoredEvent.h"
@implementation SNTXPCSyncServiceInterface
+ (NSXPCInterface *)syncServiceInterface {
NSXPCInterface *r = [NSXPCInterface interfaceWithProtocol:@protocol(SNTSyncServiceXPC)];
[r setClasses:[NSSet setWithObjects:[NSArray class], [SNTStoredEvent class], nil]
forSelector:@selector(postEventsToSyncServer:fromBundle:)
argumentIndex:0
ofReply:NO];
return r;
}
+ (NSString *)serviceID {
return @"com.google.santa.syncservice";
}
+ (MOLXPCConnection *)configuredConnection {
MOLXPCConnection *c = [[MOLXPCConnection alloc] initClientWithName:[self serviceID]
privileged:YES];
c.remoteInterface = [self syncServiceInterface];
return c;
}
@end

View File

@@ -71,7 +71,7 @@
- (void)ruleSyncLastSuccess:(void (^)(NSDate *))reply;
- (void)syncCleanRequired:(void (^)(BOOL))reply;
- (void)enableBundles:(void (^)(BOOL))reply;
- (void)enableTransitiveWhitelisting:(void (^)(BOOL))reply;
- (void)enableTransitiveRules:(void (^)(BOOL))reply;
///
/// GUI Ops

View File

@@ -29,7 +29,6 @@
#include <cstdio>
#include <cstdlib>
#include <cstring>
// TODO(rah): Consider templatizing these.
#define panic(args...) printf(args); printf("\n"); abort()
#define IOMallocAligned(sz, alignment) malloc(sz);
#define IOFreeAligned(addr, sz) free(addr)
@@ -37,6 +36,8 @@
#define OSTestAndClear(bit, addr) OSAtomicTestAndClear(bit, addr) == 0
#define OSIncrementAtomic(addr) OSAtomicIncrement64((volatile int64_t *)addr)
#define OSDecrementAtomic(addr) OSAtomicDecrement64((volatile int64_t *)addr)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
#endif // KERNEL
/**
@@ -78,6 +79,7 @@ template<typename KeyT, typename ValueT> class SantaCache {
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) ?: 1)));
if (unlikely(bucket_count_ > UINT32_MAX)) bucket_count_ = UINT32_MAX;
buckets_ = (struct bucket *)IOMallocAligned(bucket_count_ * sizeof(struct bucket), 2);
bzero(buckets_, bucket_count_ * sizeof(struct bucket));
}
@@ -197,6 +199,11 @@ template<typename KeyT, typename ValueT> class SantaCache {
if (per_bucket_counts == nullptr || array_size == nullptr || start_bucket == nullptr) return;
uint64_t start = *start_bucket;
if (start >= bucket_count_) {
*start_bucket = 0;
return;
}
uint16_t size = *array_size;
if (start + size > bucket_count_) size = bucket_count_ - start;
@@ -357,4 +364,8 @@ template<typename KeyT, typename ValueT> class SantaCache {
}
};
#ifndef KERNEL
#pragma clang diagnostic pop
#endif
#endif // SANTA__SANTA_DRIVER__SANTACACHE_H

View File

@@ -18,7 +18,7 @@
#include <string>
#include <vector>
#include "Source/santa_driver/SantaCache.h"
#include "Source/common/SantaCache.h"
@interface SantaCacheTest : XCTestCase
@end
@@ -251,7 +251,7 @@ template<> uint64_t SantaCacheHasher<S>(S const& s) {
}
- (void)testStructKeys {
auto sut = SantaCache<S, uint64_t>(10, 2);
auto sut = SantaCache<S, uint64_t>(10, 2);
S s1 = {1024, 2048};
S s2 = {4096, 8192};
@@ -265,4 +265,22 @@ template<> uint64_t SantaCacheHasher<S>(S const& s) {
XCTAssertEqual(sut.get(s3), 30);
}
- (void)testBucketCounts {
auto sut = new SantaCache<uint64_t, uint64_t>(UINT16_MAX, 1);
// These tests verify that the bucket_counts() function can't be abused
// with integer {over,under}flow issues in the input or going out-of-bounds
// on the buckets array.
uint16_t size = 2048;
uint64_t start = (UINT64_MAX - 2047);
uint16_t per_bucket_counts[2048];
sut->bucket_counts(per_bucket_counts, &size, &start);
XCTAssertEqual(start, 0, @"Check a high start can't overflow");
size = UINT16_MAX;
start = UINT16_MAX - 1;
sut->bucket_counts(per_bucket_counts, &size, &start);
XCTAssertEqual(start, 0, @"Check a large size can't overflow");
}
@end

BIN
Source/common/testdata/32bitplist vendored Executable file

Binary file not shown.

View File

@@ -1,11 +1,11 @@
load("@build_bazel_rules_apple//apple:macos.bzl", "macos_application")
licenses(["notice"]) # Apache 2.0
exports_files([
"Resources/Images.xcassets/AppIcon.appiconset/santa-hat-icon-256.png",
])
load("@build_bazel_rules_apple//apple:macos.bzl", "macos_application")
objc_library(
name = "SantaGUI_lib",
srcs = [
@@ -35,6 +35,7 @@ objc_library(
deps = [
"//Source/common:SNTBlockMessage_SantaGUI",
"//Source/common:SNTConfigurator",
"//Source/common:SNTLogging",
"//Source/common:SNTXPCControlInterface",
"//Source/common:SNTXPCNotifierInterface",
"@MOLCodesignChecker",
@@ -55,6 +56,6 @@ macos_application(
infoplists = ["Info.plist"],
minimum_os_version = "10.9",
version = "//:version",
visibility = ["//visibility:public"],
visibility = ["//:santa_package_group"],
deps = [":SantaGUI_lib"],
)

View File

@@ -38,7 +38,7 @@
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<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 macOS.
<string key="title">Santa is an application control system for macOS.
There are no user-configurable settings.</string>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>

View File

@@ -3,4 +3,4 @@
"version" : 1,
"author" : "xcode"
}
}
}

View File

@@ -16,8 +16,6 @@
#import <MOLXPCConnection/MOLXPCConnection.h>
#import <SystemExtensions/SystemExtensions.h>
#import "Source/common/SNTConfigurator.h"
#import "Source/common/SNTLogging.h"
#import "Source/common/SNTStrengthify.h"
@@ -25,7 +23,7 @@
#import "Source/santa/SNTAboutWindowController.h"
#import "Source/santa/SNTNotificationManager.h"
@interface SNTAppDelegate ()<OSSystemExtensionRequestDelegate>
@interface SNTAppDelegate ()
@property SNTAboutWindowController *aboutWindowController;
@property SNTNotificationManager *notificationManager;
@property MOLXPCConnection *daemonListener;
@@ -36,10 +34,6 @@
#pragma mark App Delegate methods
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
if (@available(macOS 10.15, *)) {
[self loadSystemExtension];
}
[self setupMenu];
self.notificationManager = [[SNTNotificationManager alloc] init];
@@ -69,20 +63,6 @@
return NO;
}
- (void)loadSystemExtension API_AVAILABLE(macos(10.15)) {
if (![[SNTConfigurator configurator] enableSystemExtension]) {
LOGI(@"EnableSystemExtension is disabled");
return;
}
LOGI(@"Requesting SystemExtension activation");
NSString *e = [SNTXPCControlInterface systemExtensionID];
dispatch_queue_t q = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
OSSystemExtensionRequest *req = [OSSystemExtensionRequest activationRequestForExtension:e
queue:q];
req.delegate = self;
[[OSSystemExtensionManager sharedManager] submitRequest:req];
}
#pragma mark Connection handling
- (void)createDaemonConnection {
@@ -143,28 +123,4 @@
[NSApp setMainMenu:mainMenu];
}
#pragma mark OSSystemExtensionRequestDelegate
- (OSSystemExtensionReplacementAction)request:(OSSystemExtensionRequest *)request
actionForReplacingExtension:(OSSystemExtensionProperties *)old
withExtension:(OSSystemExtensionProperties *)new
API_AVAILABLE(macos(10.15)) {
LOGI(@"SystemExtension \"%@\" request for replacement", request.identifier);
return OSSystemExtensionReplacementActionReplace;
}
- (void)requestNeedsUserApproval:(OSSystemExtensionRequest *)request API_AVAILABLE(macos(10.15)) {
LOGI(@"SystemExtension \"%@\" request needs user approval", request.identifier);
}
- (void)request:(OSSystemExtensionRequest *)request
didFailWithError:(NSError *)error API_AVAILABLE(macos(10.15)) {
LOGI(@"SystemExtension \"%@\" request did fail: %@", request.identifier, error);
}
- (void)request:(OSSystemExtensionRequest *)request
didFinishWithResult:(OSSystemExtensionRequestResult)result API_AVAILABLE(macos(10.15)) {
LOGI(@"SystemExtension \"%@\" request did finish: %ld", request.identifier, (long)result);
}
@end

View File

@@ -1,4 +1,4 @@
licenses(["notice"]) # Apache 2.0
licenses(["notice"])
load(
"@build_bazel_rules_apple//apple:macos.bzl",
@@ -11,7 +11,6 @@ load("//:version.bzl", "SANTA_VERSION")
cc_library(
name = "santa_driver_lib",
srcs = [
"SantaCache.h",
"SantaDecisionManager.cc",
"SantaDecisionManager.h",
"SantaDriver.cc",
@@ -23,6 +22,7 @@ cc_library(
copts = [
"-mkernel",
"-fapple-kext",
"-Wno-ossharedptr-misuse",
"-I__BAZEL_XCODE_SDKROOT__/System/Library/Frameworks/Kernel.framework/Headers",
],
defines = [
@@ -32,6 +32,7 @@ cc_library(
"SANTA_VERSION=" + SANTA_VERSION,
],
deps = [
"//Source/common:SantaCache",
"//Source/common:SNTKernelCommon",
"//Source/common:SNTLoggingKernel",
"//Source/common:SNTPrefixTreeKernel",
@@ -39,15 +40,6 @@ cc_library(
alwayslink = 1,
)
santa_unit_test(
name = "SantaCacheTest",
srcs = [
"SantaCache.h",
"SantaCacheTest.mm",
],
deps = ["//Source/common:SNTKernelCommon"],
)
macos_kernel_extension(
name = "santa_driver",
bundle_id = "com.google.santa-driver",
@@ -55,7 +47,7 @@ macos_kernel_extension(
infoplists = ["Info.plist"],
minimum_os_version = "10.9",
version = "//:version",
visibility = ["//visibility:public"],
visibility = ["//:santa_package_group"],
deps = [":santa_driver_lib"],
)

View File

@@ -185,23 +185,35 @@ void SantaDecisionManager::SetLogPort(mach_port_t port) {
}
IOMemoryDescriptor *SantaDecisionManager::GetDecisionMemoryDescriptor() const {
return decision_dataqueue_->getMemoryDescriptor();
lck_mtx_lock(decision_dataqueue_lock_);
IOMemoryDescriptor *r = decision_dataqueue_->getMemoryDescriptor();
lck_mtx_unlock(decision_dataqueue_lock_);
return r;
}
IOMemoryDescriptor *SantaDecisionManager::GetLogMemoryDescriptor() const {
return log_dataqueue_->getMemoryDescriptor();
lck_mtx_lock(log_dataqueue_lock_);
IOMemoryDescriptor *r = log_dataqueue_->getMemoryDescriptor();
lck_mtx_unlock(log_dataqueue_lock_);
return r;
}
#pragma mark Listener Control
kern_return_t SantaDecisionManager::StartListener() {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
vnode_listener_ = kauth_listen_scope(
KAUTH_SCOPE_VNODE, vnode_scope_callback, reinterpret_cast<void *>(this));
#pragma clang diagnostic pop
if (!vnode_listener_) return kIOReturnInternalError;
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
fileop_listener_ = kauth_listen_scope(
KAUTH_SCOPE_FILEOP, fileop_scope_callback,
reinterpret_cast<void *>(this));
#pragma clang diagnostic pop
if (!fileop_listener_) return kIOReturnInternalError;
LOGD("Listeners started.");
@@ -210,11 +222,14 @@ kern_return_t SantaDecisionManager::StartListener() {
}
kern_return_t SantaDecisionManager::StopListener() {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
kauth_unlisten_scope(vnode_listener_);
vnode_listener_ = nullptr;
kauth_unlisten_scope(fileop_listener_);
fileop_listener_ = nullptr;
#pragma clang diagnostic pop
// Wait for any active invocations to finish before returning
do {
@@ -601,7 +616,7 @@ int SantaDecisionManager::VnodeCallback(const kauth_cred_t cred,
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);
uint64_t val = ((uint64_t)pid << 32) | ((uint64_t)ppid & 0xFFFFFFFF);
vnode_pid_map_->set(vnode_id, val);
if (returnedAction == ACTION_RESPOND_ALLOW_COMPILER && ppid != 0) {
// Do some additional bookkeeping for compilers:
@@ -659,8 +674,8 @@ void SantaDecisionManager::FileOpCallback(
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);
message->pid = (pid_t)(val >> 32);
message->ppid = (pid_t)(val & ~0xFFFFFFFF00000000);
}
PostToLogQueue(message);
@@ -801,7 +816,7 @@ extern "C" int vnode_scope_callback(
// We only care about regular files.
if (vnode_vtype(vp) != VREG) return KAUTH_RESULT_DEFER;
if ((action & KAUTH_VNODE_EXECUTE) && !(action & KAUTH_VNODE_ACCESS)) { // NOLINT
if ((action & (int)KAUTH_VNODE_EXECUTE) && !(action & (int)KAUTH_VNODE_ACCESS)) {
sdm->IncrementListenerInvocations();
int result = sdm->VnodeCallback(credential,
reinterpret_cast<vfs_context_t>(arg0),
@@ -809,9 +824,9 @@ extern "C" int vnode_scope_callback(
reinterpret_cast<int *>(arg3));
sdm->DecrementListenerInvocations();
return result;
} else if (action & KAUTH_VNODE_WRITE_DATA || action & KAUTH_VNODE_APPEND_DATA) {
} else if (action & (int)KAUTH_VNODE_WRITE_DATA || action & (int)KAUTH_VNODE_APPEND_DATA) {
sdm->IncrementListenerInvocations();
if (!(action & KAUTH_VNODE_ACCESS)) { // NOLINT
if (!(action & (int)KAUTH_VNODE_ACCESS)) {
auto vnode_id = sdm->GetVnodeIDForVnode(reinterpret_cast<vfs_context_t>(arg0), vp);
sdm->RemoveFromCache(vnode_id);
}

View File

@@ -23,10 +23,10 @@
#include <sys/proc.h>
#include <sys/vnode.h>
#include "Source/common/SantaCache.h"
#include "Source/common/SNTKernelCommon.h"
#include "Source/common/SNTLogging.h"
#include "Source/common/SNTPrefixTree.h"
#include "Source/santa_driver/SantaCache.h"
///
/// SantaDecisionManager is responsible for intercepting Vnode execute actions

View File

@@ -293,7 +293,7 @@ IOReturn SantaDriverClient::externalMethod(
{ &SantaDriverClient::filemod_prefix_filter_reset, 0, 0, 0, 0 },
};
if (selector > static_cast<UInt32>(kSantaUserClientNMethods)) {
if (selector >= static_cast<UInt32>(kSantaUserClientNMethods)) {
return kIOReturnBadArgument;
}

View File

@@ -360,7 +360,7 @@
}
// Now replace the contents of the test file (which is cached) with the contents of /bin/ed,
// which is 'blacklisted' by SHA-256 during the tests.
// which is blocked by SHA-256 during the tests.
FILE *infile = fopen("/bin/ed", "r");
FILE *outfile = fopen(target.UTF8String, "w");
int ch;

View File

@@ -26,6 +26,6 @@ macos_command_line_application(
infoplists = ["Info.plist"],
minimum_os_version = "10.9",
version = "//:version",
visibility = ["//visibility:public"],
visibility = ["//:santa_package_group"],
deps = [":santabs_lib"],
)

View File

@@ -75,7 +75,7 @@ macos_command_line_application(
infoplists = ["Info.plist"],
minimum_os_version = "10.9",
version = "//:version",
visibility = ["//visibility:public"],
visibility = ["//:santa_package_group"],
deps = [":santactl_lib"],
)

View File

@@ -54,16 +54,16 @@ REGISTER_COMMAND_NAME(@"checkcache")
[[self.daemonConn remoteObjectProxy] checkCacheForVnodeID:vnodeID
withReply:^(santa_action_t action) {
if (action == ACTION_RESPOND_ALLOW) {
LOGI(@"File exists in [whitelist] kernel cache");
LOGI(@"File exists in [allowlist] kernel cache");
exit(0);
} else if (action == ACTION_RESPOND_DENY) {
LOGI(@"File exists in [blacklist] kernel cache");
LOGI(@"File exists in [blocklist] kernel cache");
exit(0);
} else if (action == ACTION_RESPOND_ALLOW_COMPILER) {
LOGI(@"File exists in [whitelist compiler] kernel cache");
LOGI(@"File exists in [allowlist compiler] kernel cache");
exit(0);
} else if (action == ACTION_RESPOND_ALLOW_PENDING_TRANSITIVE) {
LOGI(@"File exists in [whitelist pending_transitive] kernel cache");
LOGI(@"File exists in [allowlist pending_transitive] kernel cache");
exit(0);
} else if (action == ACTION_UNSET) {
LOGE(@"File does not exist in cache");

View File

@@ -366,7 +366,7 @@ REGISTER_COMMAND_NAME(@"fileinfo")
return kCommunicationErrorMsg;
} else {
NSMutableString *output =
(SNTEventStateAllow & state) ? @"Whitelisted".mutableCopy : @"Blacklisted".mutableCopy;
(SNTEventStateAllow & state) ? @"Allowed".mutableCopy : @"Blocked".mutableCopy;
switch (state) {
case SNTEventStateAllowUnknown:
case SNTEventStateBlockUnknown:

View File

@@ -49,10 +49,10 @@ REGISTER_COMMAND_NAME(@"rule")
+ (NSString *)longHelpText {
return (@"Usage: santactl rule [options]\n"
@" One of:\n"
@" --whitelist: add to whitelist\n"
@" --blacklist: add to blacklist\n"
@" --silent-blacklist: add to silent blacklist\n"
@" --compiler: whitelist and mark as a compiler\n"
@" --allow: add to allow\n"
@" --block: add to block\n"
@" --silent-block: add to silent block\n"
@" --compiler: allow and mark as a compiler\n"
@" --remove: remove existing rule\n"
@" --check: check for an existing rule\n"
@"\n"
@@ -96,14 +96,17 @@ REGISTER_COMMAND_NAME(@"rule")
for (NSUInteger i = 0; i < arguments.count; ++i) {
NSString *arg = arguments[i];
if ([arg caseInsensitiveCompare:@"--whitelist"] == NSOrderedSame) {
newRule.state = SNTRuleStateWhitelist;
} else if ([arg caseInsensitiveCompare:@"--blacklist"] == NSOrderedSame) {
newRule.state = SNTRuleStateBlacklist;
} else if ([arg caseInsensitiveCompare:@"--silent-blacklist"] == NSOrderedSame) {
newRule.state = SNTRuleStateSilentBlacklist;
if ([arg caseInsensitiveCompare:@"--allow"] == NSOrderedSame ||
[arg caseInsensitiveCompare:@"--whitelist"] == NSOrderedSame) {
newRule.state = SNTRuleStateAllow;
} else if ([arg caseInsensitiveCompare:@"--block"] == NSOrderedSame ||
[arg caseInsensitiveCompare:@"--blacklist"] == NSOrderedSame) {
newRule.state = SNTRuleStateBlock;
} else if ([arg caseInsensitiveCompare:@"--silent-block"] == NSOrderedSame ||
[arg caseInsensitiveCompare:@"--silent-blacklist"] == NSOrderedSame) {
newRule.state = SNTRuleStateSilentBlock;
} else if ([arg caseInsensitiveCompare:@"--compiler"] == NSOrderedSame) {
newRule.state = SNTRuleStateWhitelistCompiler;
newRule.state = SNTRuleStateAllowCompiler;
} else if ([arg caseInsensitiveCompare:@"--remove"] == NSOrderedSame) {
newRule.state = SNTRuleStateRemove;
} else if ([arg caseInsensitiveCompare:@"--check"] == NSOrderedSame) {
@@ -190,7 +193,7 @@ REGISTER_COMMAND_NAME(@"rule")
fileSHA256:fileSHA256
certificateSHA256:certificateSHA256
reply:^(SNTEventState s) {
output = (SNTEventStateAllow & s) ? @"Whitelisted".mutableCopy : @"Blacklisted".mutableCopy;
output = (SNTEventStateAllow & s) ? @"Allowed".mutableCopy : @"Blocked".mutableCopy;
switch (s) {
case SNTEventStateAllowUnknown:
case SNTEventStateBlockUnknown:
@@ -241,7 +244,7 @@ REGISTER_COMMAND_NAME(@"rule")
[[daemonConn remoteObjectProxy] databaseRuleForBinarySHA256:fileSHA256
certificateSHA256:certificateSHA256
reply:^(SNTRule *r) {
if (r.state == SNTRuleStateWhitelistTransitive) {
if (r.state == SNTRuleStateAllowTransitive) {
NSDate *date = [NSDate dateWithTimeIntervalSinceReferenceDate:r.timestamp];
[output appendString:[NSString stringWithFormat:@"\nlast access date: %@", [date description]]];
}

View File

@@ -86,9 +86,11 @@ REGISTER_COMMAND_NAME(@"status")
SNTConfigurator *configurator = [SNTConfigurator configurator];
BOOL cachingEnabled = (![configurator enableSystemExtension] || [configurator enableSysxCache]);
// Kext status
__block uint64_t rootCacheCount = -1, nonRootCacheCount = -1;
if (![configurator enableSystemExtension]) {
if (cachingEnabled) {
dispatch_group_enter(group);
[[self.daemonConn remoteObjectProxy] cacheCounts:^(uint64_t rootCache, uint64_t nonRootCache) {
rootCacheCount = rootCache;
@@ -157,10 +159,10 @@ REGISTER_COMMAND_NAME(@"status")
}];
}
__block BOOL transitiveWhitelistingEnabled = NO;
__block BOOL enableTransitiveRules = NO;
dispatch_group_enter(group);
[[self.daemonConn remoteObjectProxy] enableTransitiveWhitelisting:^(BOOL response) {
transitiveWhitelistingEnabled = response;
[[self.daemonConn remoteObjectProxy] enableTransitiveRules:^(BOOL response) {
enableTransitiveRules = response;
dispatch_group_leave(group);
}];
@@ -203,11 +205,11 @@ REGISTER_COMMAND_NAME(@"status")
@"last_successful_rule" : ruleSyncLastSuccessStr ?: @"null",
@"push_notifications" : pushNotifications ? @"Connected" : @"Disconnected",
@"bundle_scanning" : @(enableBundles),
@"transitive_whitelisting" : @(transitiveWhitelistingEnabled),
@"transitive_rules" : @(enableTransitiveRules),
},
} mutableCopy];
if (![configurator enableSystemExtension]) {
stats[@"kernel"] = @{
if (cachingEnabled) {
stats[@"cache"] = @{
@"root_cache_count" : @(rootCacheCount),
@"non_root_cache_count": @(nonRootCacheCount),
};
@@ -224,8 +226,8 @@ REGISTER_COMMAND_NAME(@"status")
printf(" %-25s | %s\n", "File Logging", (fileLogging ? "Yes" : "No"));
printf(" %-25s | %lld (Peak: %.2f%%)\n", "Watchdog CPU Events", cpuEvents, cpuPeak);
printf(" %-25s | %lld (Peak: %.2fMB)\n", "Watchdog RAM Events", ramEvents, ramPeak);
if (![configurator enableSystemExtension]) {
printf(">>> Kernel Info\n");
if (cachingEnabled) {
printf(">>> Cache Info\n");
printf(" %-25s | %lld\n", "Root cache count", rootCacheCount);
printf(" %-25s | %lld\n", "Non-root cache count", nonRootCacheCount);
}
@@ -245,8 +247,8 @@ REGISTER_COMMAND_NAME(@"status")
printf(" %-25s | %s\n", "Push Notifications",
(pushNotifications ? "Connected" : "Disconnected"));
printf(" %-25s | %s\n", "Bundle Scanning", (enableBundles ? "Yes" : "No"));
printf(" %-25s | %s\n", "Transitive Whitelisting",
(transitiveWhitelistingEnabled ? "Yes" : "No"));
printf(" %-25s | %s\n", "Transitive Rules",
(enableTransitiveRules? "Yes" : "No"));
}
}

View File

@@ -38,8 +38,9 @@ REGISTER_COMMAND_NAME(@"sync")
return YES;
}
// Connect to santad while we are root, so that we pass the XPC authentication.
+ (BOOL)requiresDaemonConn {
return NO;
return YES;
}
+ (NSString *)shortHelpText {
@@ -55,9 +56,6 @@ REGISTER_COMMAND_NAME(@"sync")
}
- (void)runWithArguments:(NSArray *)arguments {
// Connect to santad while we are root, so that we pass the XPC authentication
[self.daemonConn resume];
// Ensure we have no privileges
if (!DropRootPrivileges()) {
LOGE(@"Failed to drop root privileges. Exiting.");

View File

@@ -29,19 +29,23 @@ extern NSString *const kClientMode;
extern NSString *const kClientModeMonitor;
extern NSString *const kClientModeLockdown;
extern NSString *const kCleanSync;
extern NSString *const kWhitelistRegex;
extern NSString *const kBlacklistRegex;
extern NSString *const kAllowedPathRegex;
extern NSString *const kAllowedPathRegexDeprecated;
extern NSString *const kBlockedPathRegex;
extern NSString *const kBlockedPathRegexDeprecated;
extern NSString *const kBinaryRuleCount;
extern NSString *const kCertificateRuleCount;
extern NSString *const kCompilerRuleCount;
extern NSString *const kTransitiveRuleCount;
extern NSString *const kFullSyncInterval;
extern NSString *const kFCMToken;
extern NSString *const kFCMFullSyncInterval;
extern NSString *const kFCMGlobalRuleSyncDeadline;
extern NSString *const kEnableBundles;
extern NSString *const kEnableBundles_OLD;
extern NSString *const kEnableTransitiveWhitelisting;
extern NSString *const kEnableTransitiveWhitelisting_OLD;
extern NSString *const kEnableBundlesDeprecated;
extern NSString *const kEnableTransitiveRules;
extern NSString *const kEnableTransitiveRulesDeprecated;
extern NSString *const kEnableTransitiveRulesSuperDeprecated;
extern NSString *const kEvents;
extern NSString *const kFileSHA256;
@@ -90,10 +94,14 @@ extern NSString *const kEventUploadBundleBinaries;
extern NSString *const kRules;
extern NSString *const kRuleSHA256;
extern NSString *const kRulePolicy;
extern NSString *const kRulePolicyWhitelist;
extern NSString *const kRulePolicyWhitelistCompiler;
extern NSString *const kRulePolicyBlacklist;
extern NSString *const kRulePolicySilentBlacklist;
extern NSString *const kRulePolicyAllowlist;
extern NSString *const kRulePolicyAllowlistDeprecated;
extern NSString *const kRulePolicyAllowlistCompiler;
extern NSString *const kRulePolicyAllowlistCompilerDeprecated;
extern NSString *const kRulePolicyBlocklist;
extern NSString *const kRulePolicyBlocklistDeprecated;
extern NSString *const kRulePolicySilentBlocklist;
extern NSString *const kRulePolicySilentBlocklistDeprecated;
extern NSString *const kRulePolicyRemove;
extern NSString *const kRuleType;
extern NSString *const kRuleTypeBinary;

View File

@@ -29,21 +29,24 @@ NSString *const kClientMode = @"client_mode";
NSString *const kClientModeMonitor = @"MONITOR";
NSString *const kClientModeLockdown = @"LOCKDOWN";
NSString *const kCleanSync = @"clean_sync";
NSString *const kWhitelistRegex = @"whitelist_regex";
NSString *const kBlacklistRegex = @"blacklist_regex";
NSString *const kAllowedPathRegex = @"allowed_path_regex";
NSString *const kAllowedPathRegexDeprecated = @"whitelist_regex";
NSString *const kBlockedPathRegex = @"blocked_path_regex";
NSString *const kBlockedPathRegexDeprecated = @"blacklist_regex";
NSString *const kBinaryRuleCount = @"binary_rule_count";
NSString *const kCertificateRuleCount = @"certificate_rule_count";
NSString *const kCompilerRuleCount = @"compiler_rule_count";
NSString *const kTransitiveRuleCount = @"transitive_rule_count";
NSString *const kFullSyncInterval = @"full_sync_interval";
NSString *const kFCMToken = @"fcm_token";
NSString *const kFCMFullSyncInterval = @"fcm_full_sync_interval";
NSString *const kFCMGlobalRuleSyncDeadline = @"fcm_global_rule_sync_deadline";
// NOTE: Both of the _OLD values will be removed at some indeterminate point in the future.
NSString *const kEnableBundles = @"enable_bundles";
NSString *const kEnableBundles_OLD = @"bundles_enabled";
NSString *const kEnableTransitiveWhitelisting = @"enabled_transitive_whitelisting";
NSString *const kEnableTransitiveWhitelisting_OLD = @"transitive_whitelisting_enabled";
NSString *const kEnableBundlesDeprecated = @"bundles_enabled";
NSString *const kEnableTransitiveRules = @"enable_transitive_rules";
NSString *const kEnableTransitiveRulesDeprecated = @"enabled_transitive_whitelisting";
NSString *const kEnableTransitiveRulesSuperDeprecated = @"transitive_whitelisting_enabled";
NSString *const kEvents = @"events";
NSString *const kFileSHA256 = @"file_sha256";
@@ -92,10 +95,14 @@ NSString *const kEventUploadBundleBinaries = @"event_upload_bundle_binaries";
NSString *const kRules = @"rules";
NSString *const kRuleSHA256 = @"sha256";
NSString *const kRulePolicy = @"policy";
NSString *const kRulePolicyWhitelist = @"WHITELIST";
NSString *const kRulePolicyWhitelistCompiler = @"WHITELIST_COMPILER";
NSString *const kRulePolicyBlacklist = @"BLACKLIST";
NSString *const kRulePolicySilentBlacklist = @"SILENT_BLACKLIST";
NSString *const kRulePolicyAllowlist = @"ALLOWLIST";
NSString *const kRulePolicyAllowlistDeprecated = @"WHITELIST";
NSString *const kRulePolicyAllowlistCompiler = @"ALLOWLIST_COMPILER";
NSString *const kRulePolicyAllowlistCompilerDeprecated = @"WHITELIST_COMPILER";
NSString *const kRulePolicyBlocklist = @"BLOCKLIST";
NSString *const kRulePolicyBlocklistDeprecated = @"BLACKLIST";
NSString *const kRulePolicySilentBlocklist = @"SILENT_BLOCKLIST";
NSString *const kRulePolicySilentBlocklistDeprecated = @"SILENT_BLACKLIST";
NSString *const kRulePolicyRemove = @"REMOVE";
NSString *const kRuleType = @"rule_type";
NSString *const kRuleTypeBinary = @"BINARY";

View File

@@ -47,13 +47,15 @@ static NSString *const kFCMTargetHostIDKey = @"target_host_id";
@property(nonatomic) NSCache *dispatchLock;
// whitelistNotifications dictionary stores info from FCM messages. The binary/bundle hash is used
// allowlistNotifications dictionary stores info from FCM messages. The binary/bundle hash is used
// as a key mapping to values that are themselves dictionaries. These dictionary values contain the
// name of the binary/bundle and a count of associated binary rules.
@property(nonatomic) NSMutableDictionary *whitelistNotifications;
@property(nonatomic) NSMutableDictionary *allowlistNotifications;
// whitelistNotificationQueue is used to serialize access to the whitelistNotifications dictionary.
@property(nonatomic) NSOperationQueue *whitelistNotificationQueue;
// allowlistNotificationQueue is used to serialize access to the allowlistNotifications dictionary.
@property(nonatomic) NSOperationQueue *allowlistNotificationQueue;
@property NSUInteger fullSyncInterval;
@property NSUInteger FCMFullSyncInterval;
@property NSUInteger FCMGlobalRuleSyncDeadline;
@@ -106,8 +108,8 @@ static void reachabilityHandler(
[self lockAction:kRuleSync];
SNTCommandSyncState *syncState = [self createSyncState];
syncState.targetedRuleSync = self.targetedRuleSync;
syncState.whitelistNotifications = self.whitelistNotifications;
syncState.whitelistNotificationQueue = self.whitelistNotificationQueue;
syncState.allowlistNotifications = self.allowlistNotifications;
syncState.allowlistNotificationQueue = self.allowlistNotificationQueue;
SNTCommandSyncRuleDownload *p = [[SNTCommandSyncRuleDownload alloc] initWithState:syncState];
if ([p sync]) {
LOGD(@"Rule download complete");
@@ -118,10 +120,11 @@ static void reachabilityHandler(
[self unlockAction:kRuleSync];
}];
_dispatchLock = [[NSCache alloc] init];
_whitelistNotifications = [NSMutableDictionary dictionary];
_whitelistNotificationQueue = [[NSOperationQueue alloc] init];
_whitelistNotificationQueue.maxConcurrentOperationCount = 1; // make this a serial queue
_allowlistNotifications = [NSMutableDictionary dictionary];
_allowlistNotificationQueue = [[NSOperationQueue alloc] init];
_allowlistNotificationQueue.maxConcurrentOperationCount = 1; // make this a serial queue
_fullSyncInterval = kDefaultFullSyncInterval;
_eventBatchSize = kDefaultEventBatchSize;
_FCMFullSyncInterval = kDefaultFCMFullSyncInterval;
_FCMGlobalRuleSyncDeadline = kDefaultFCMGlobalRuleSyncDeadline;
@@ -243,8 +246,8 @@ static void reachabilityHandler(
NSString *fileHash = message[kFCMFileHashKey];
NSString *fileName = message[kFCMFileNameKey];
if (fileName && fileHash) {
[self.whitelistNotificationQueue addOperationWithBlock:^{
self.whitelistNotifications[fileHash] = @{ kFileName : fileName }.mutableCopy;
[self.allowlistNotificationQueue addOperationWithBlock:^{
self.allowlistNotifications[fileHash] = @{ kFileName : fileName }.mutableCopy;
}];
}
@@ -350,10 +353,11 @@ static void reachabilityHandler(
self.FCMGlobalRuleSyncDeadline = syncState.FCMGlobalRuleSyncDeadline;
[self listenForPushNotificationsWithSyncState:syncState];
} else if (syncState.daemon) {
LOGD(@"FCMToken not provided. Sync every %lu min.", kDefaultFullSyncInterval / 60);
LOGD(@"FCMToken not provided. Sync every %lu min.", syncState.fullSyncInterval / 60);
[self.FCMClient disconnect];
self.FCMClient = nil;
[self rescheduleTimerQueue:self.fullSyncTimer secondsFromNow:kDefaultFullSyncInterval];
self.fullSyncInterval = syncState.fullSyncInterval;
[self rescheduleTimerQueue:self.fullSyncTimer secondsFromNow:self.fullSyncInterval];
}
return [self eventUploadWithSyncState:syncState];
@@ -478,6 +482,9 @@ static void reachabilityHandler(
syncState.daemonConn = self.daemonConn;
syncState.daemon = self.daemon;
syncState.compressedContentEncoding =
config.enableBackwardsCompatibleContentEncoding ? @"zlib" : @"deflate";
dispatch_group_wait(group, dispatch_time(DISPATCH_TIME_NOW, 5 * NSEC_PER_SEC));
return syncState;
}

View File

@@ -49,16 +49,16 @@
[[self.daemonConn remoteObjectProxy] setSyncCleanRequired:NO reply:replyBlock];
}
// Update whitelist/blacklist regexes
if (self.syncState.whitelistRegex) {
// Update allowlist/blocklist regexes
if (self.syncState.allowlistRegex) {
dispatch_group_enter(group);
[[self.daemonConn remoteObjectProxy] setWhitelistPathRegex:self.syncState.whitelistRegex
reply:replyBlock];
[[self.daemonConn remoteObjectProxy] setAllowedPathRegex:self.syncState.allowlistRegex
reply:replyBlock];
}
if (self.syncState.blacklistRegex) {
if (self.syncState.blocklistRegex) {
dispatch_group_enter(group);
[[self.daemonConn remoteObjectProxy] setBlacklistPathRegex:self.syncState.blacklistRegex
reply:replyBlock];
[[self.daemonConn remoteObjectProxy] setBlockedPathRegex:self.syncState.blocklistRegex
reply:replyBlock];
}
// Update last sync success

View File

@@ -87,20 +87,17 @@
dispatch_group_enter(group);
NSNumber *enableBundles = resp[kEnableBundles];
if (!enableBundles) {
enableBundles = resp[kEnableBundles_OLD];
}
if (!enableBundles) enableBundles = resp[kEnableBundlesDeprecated];
[[self.daemonConn remoteObjectProxy] setEnableBundles:[enableBundles boolValue] reply:^{
dispatch_group_leave(group);
}];
dispatch_group_enter(group);
NSNumber *enableTransitiveWhitelisting = resp[kEnableTransitiveWhitelisting];
if (!enableTransitiveWhitelisting) {
enableTransitiveWhitelisting = resp[kEnableTransitiveWhitelisting_OLD];
}
BOOL enabled = [enableTransitiveWhitelisting boolValue];
[[self.daemonConn remoteObjectProxy] setEnableTransitiveWhitelisting:enabled reply:^{
NSNumber *enableTransitiveRules = resp[kEnableTransitiveRules];
if (!enableTransitiveRules) enableTransitiveRules = resp[kEnableTransitiveRulesDeprecated];
if (!enableTransitiveRules) enableTransitiveRules = resp[kEnableTransitiveRulesSuperDeprecated];
BOOL enabled = [enableTransitiveRules boolValue];
[[self.daemonConn remoteObjectProxy] setEnableTransitiveRules:enabled reply:^{
dispatch_group_leave(group);
}];
@@ -108,12 +105,17 @@
self.syncState.FCMToken = resp[kFCMToken];
// Don't let these go too low
NSUInteger value = [resp[kFCMFullSyncInterval] unsignedIntegerValue];
self.syncState.FCMFullSyncInterval =
(value < kDefaultFullSyncInterval) ? kDefaultFCMFullSyncInterval : value;
value = [resp[kFCMGlobalRuleSyncDeadline] unsignedIntegerValue];
NSUInteger FCMIntervalValue = [resp[kFCMFullSyncInterval] unsignedIntegerValue];
self.syncState.FCMFullSyncInterval = (FCMIntervalValue < kDefaultFullSyncInterval)
? kDefaultFCMFullSyncInterval
: FCMIntervalValue;
FCMIntervalValue = [resp[kFCMGlobalRuleSyncDeadline] unsignedIntegerValue];
self.syncState.FCMGlobalRuleSyncDeadline =
(value < 60) ? kDefaultFCMGlobalRuleSyncDeadline : value;
(FCMIntervalValue < 60) ? kDefaultFCMGlobalRuleSyncDeadline : FCMIntervalValue;
// Check if our sync interval has changed
NSUInteger intervalValue = [resp[kFullSyncInterval] unsignedIntegerValue];
self.syncState.fullSyncInterval = (intervalValue < 60) ? kDefaultFullSyncInterval : intervalValue;
if ([resp[kClientMode] isEqual:kClientModeMonitor]) {
self.syncState.clientMode = SNTClientModeMonitor;
@@ -121,12 +123,16 @@
self.syncState.clientMode = SNTClientModeLockdown;
}
if ([resp[kWhitelistRegex] isKindOfClass:[NSString class]]) {
self.syncState.whitelistRegex = resp[kWhitelistRegex];
if ([resp[kAllowedPathRegex] isKindOfClass:[NSString class]]) {
self.syncState.allowlistRegex = resp[kAllowedPathRegex];
} else if ([resp[kAllowedPathRegexDeprecated] isKindOfClass:[NSString class]]) {
self.syncState.allowlistRegex = resp[kAllowedPathRegexDeprecated];
}
if ([resp[kBlacklistRegex] isKindOfClass:[NSString class]]) {
self.syncState.blacklistRegex = resp[kBlacklistRegex];
if ([resp[kBlockedPathRegex] isKindOfClass:[NSString class]]) {
self.syncState.blocklistRegex = resp[kBlockedPathRegex];
} else if ([resp[kBlockedPathRegexDeprecated] isKindOfClass:[NSString class]]) {
self.syncState.blocklistRegex = resp[kBlockedPathRegexDeprecated];
}
if ([resp[kCleanSync] boolValue]) {

View File

@@ -60,11 +60,11 @@
}];
dispatch_semaphore_wait(sema, dispatch_time(DISPATCH_TIME_NOW, 5 * NSEC_PER_SEC));
LOGI(@"Added %lu rules", newRules.count);
LOGI(@"Processed %lu rules", newRules.count);
// Send out push notifications about any newly whitelisted binaries
// Send out push notifications about any newly allowed binaries
// that had been previously blocked by santad.
[self.syncState.whitelistNotificationQueue addOperationWithBlock:^{
[self.syncState.allowlistNotificationQueue addOperationWithBlock:^{
[self announceUnblockingRules:newRules];
}];
@@ -82,32 +82,38 @@
NSDictionary *requestDict = cursor ? @{kCursor : cursor} : @{};
NSDictionary *response = [self performRequest:[self requestWithDictionary:requestDict]];
if (![response isKindOfClass:[NSDictionary class]]) {
if (![response isKindOfClass:[NSDictionary class]] ||
![response[kRules] isKindOfClass:[NSArray class]]) {
return nil;
}
uint32_t count = 0;
for (NSDictionary *ruleDict in response[kRules]) {
SNTRule *rule = [self ruleFromDictionary:ruleDict];
if (rule) [newRules addObject:rule];
if (rule) {
[newRules addObject:rule];
count++;
}
}
LOGI(@"Received %u rules", count);
cursor = response[kCursor];
} while (cursor);
return newRules;
}
// Send out push notifications for whitelisted bundles/binaries whose rule download was preceded by
// Send out push notifications for allowed bundles/binaries whose rule download was preceded by
// an associated announcing FCM message.
- (void)announceUnblockingRules:(NSArray<SNTRule *> *)newRules {
if (!self.syncState.targetedRuleSync) return;
NSMutableArray *processed = [NSMutableArray array];
for (NSString *key in self.syncState.whitelistNotifications) {
for (NSString *key in self.syncState.allowlistNotifications) {
// Each notifier object is a dictionary with name and count keys. If the count has been
// decremented to zero, then this means that we have downloaded all of the rules associated with
// this SHA256 hash (which might be a bundle hash or a binary hash), in which case we are OK to
// show a notification that the named bundle/binary can be run.
NSDictionary *notifier = self.syncState.whitelistNotifications[key];
NSDictionary *notifier = self.syncState.allowlistNotifications[key];
NSNumber *remaining = notifier[kFileBundleBinaryCount];
if (remaining && [remaining intValue] == 0) {
[processed addObject:key];
@@ -117,8 +123,8 @@
}
}
// Remove all entries from whitelistNotifications dictionary that had zero count.
[self.syncState.whitelistNotifications removeObjectsForKeys:processed];
// Remove all entries from allowlistNotifications dictionary that had zero count.
[self.syncState.allowlistNotifications removeObjectsForKeys:processed];
}
@@ -133,14 +139,18 @@
if (newRule.shasum.length != 64) return nil;
NSString *policyString = dict[kRulePolicy];
if ([policyString isEqual:kRulePolicyWhitelist]) {
newRule.state = SNTRuleStateWhitelist;
} else if ([policyString isEqual:kRulePolicyWhitelistCompiler]) {
newRule.state = SNTRuleStateWhitelistCompiler;
} else if ([policyString isEqual:kRulePolicyBlacklist]) {
newRule.state = SNTRuleStateBlacklist;
} else if ([policyString isEqual:kRulePolicySilentBlacklist]) {
newRule.state = SNTRuleStateSilentBlacklist;
if ([policyString isEqual:kRulePolicyAllowlist] ||
[policyString isEqual:kRulePolicyAllowlistDeprecated]) {
newRule.state = SNTRuleStateAllow;
} else if ([policyString isEqual:kRulePolicyAllowlistCompiler] ||
[policyString isEqual:kRulePolicyAllowlistCompilerDeprecated]) {
newRule.state = SNTRuleStateAllowCompiler;
} else if ([policyString isEqual:kRulePolicyBlocklist] ||
[policyString isEqual:kRulePolicyBlocklistDeprecated]) {
newRule.state = SNTRuleStateBlock;
} else if ([policyString isEqual:kRulePolicySilentBlocklist] ||
[policyString isEqual:kRulePolicySilentBlocklistDeprecated]) {
newRule.state = SNTRuleStateSilentBlock;
} else if ([policyString isEqual:kRulePolicyRemove]) {
newRule.state = SNTRuleStateRemove;
} else {
@@ -162,7 +172,7 @@
}
// Check rule for extra notification related info.
if (newRule.state == SNTRuleStateWhitelist || newRule.state == SNTRuleStateWhitelistCompiler) {
if (newRule.state == SNTRuleStateAllow || newRule.state == SNTRuleStateAllowCompiler) {
// primaryHash is the bundle hash if there was a bundle hash included in the rule, otherwise
// it is simply the binary hash.
NSString *primaryHash = dict[kFileBundleHash];
@@ -171,10 +181,10 @@
}
// As we read in rules, we update the "remaining count" information stored in
// whitelistNotifications. This count represents the number of rules associated with the primary
// allowlistNotifications. This count represents the number of rules associated with the primary
// hash that still need to be downloaded and added.
[self.syncState.whitelistNotificationQueue addOperationWithBlock:^{
NSMutableDictionary *notifier = self.syncState.whitelistNotifications[primaryHash];
[self.syncState.allowlistNotificationQueue addOperationWithBlock:^{
NSMutableDictionary *notifier = self.syncState.allowlistNotifications[primaryHash];
if (notifier) {
NSNumber *ruleCount = dict[kFileBundleBinaryCount];
NSNumber *remaining = notifier[kFileBundleBinaryCount];

View File

@@ -70,7 +70,7 @@
NSData *compressed = [requestBody zlibCompressed];
if (compressed) {
requestBody = compressed;
[req setValue:@"zlib" forHTTPHeaderField:@"Content-Encoding"];
[req setValue:self.syncState.compressedContentEncoding forHTTPHeaderField:@"Content-Encoding"];
}
[req setHTTPBody:requestBody];

View File

@@ -35,6 +35,10 @@
/// An XSRF token to send in the headers with each request.
@property NSString *xsrfToken;
/// Full sync interval in seconds without FCM to update kDefaultFullSyncInterval => when FCM
/// is not used, defaults to 10m.
@property NSUInteger fullSyncInterval;
/// An FCM token to subscribe to push notifications.
@property(copy) NSString *FCMToken;
@@ -50,8 +54,8 @@
/// Settings sent from server during preflight that are set during postflight.
@property SNTClientMode clientMode;
@property NSString *whitelistRegex;
@property NSString *blacklistRegex;
@property NSString *allowlistRegex;
@property NSString *blocklistRegex;
/// Clean sync flag, if True, all existing rules should be deleted before inserting any new rules.
@property BOOL cleanSync;
@@ -69,9 +73,13 @@
@property BOOL targetedRuleSync;
/// Reference to the sync manager's ruleSyncCache. Used to lookup binary names for notifications.
@property(weak) NSMutableDictionary *whitelistNotifications;
@property(weak) NSMutableDictionary *allowlistNotifications;
/// Reference to the serial operation queue used for accessing whitelistNotifications.
@property(weak) NSOperationQueue *whitelistNotificationQueue;
/// Reference to the serial operation queue used for accessing allowlistNotifications.
@property(weak) NSOperationQueue *allowlistNotificationQueue;
/// The header value for ContentEncoding when sending compressed content.
/// Either "deflate" (default) or "zlib".
@property(copy) NSString *compressedContentEncoding;
@end

View File

@@ -184,8 +184,8 @@
XCTAssertTrue([sut sync]);
XCTAssertEqual(self.syncState.clientMode, SNTClientModeMonitor);
XCTAssertEqual(self.syncState.eventBatchSize, 100);
XCTAssertNil(self.syncState.whitelistRegex);
XCTAssertNil(self.syncState.blacklistRegex);
XCTAssertNil(self.syncState.allowlistRegex);
XCTAssertNil(self.syncState.blocklistRegex);
}
- (void)testPreflightDatabaseCounts {
@@ -375,15 +375,15 @@
NSArray *rules = @[
[[SNTRule alloc] initWithShasum:@"ee382e199f7eda58863a93a7854b930ade35798bc6856ee8e6ab6ce9277f0eab"
state:SNTRuleStateBlacklist
state:SNTRuleStateBlock
type:SNTRuleTypeBinary
customMsg:@""],
[[SNTRule alloc] initWithShasum:@"46f8c706d0533a54554af5fc163eea704f10c08b30f8a5db12bfdc04fb382fc3"
state:SNTRuleStateWhitelist
state:SNTRuleStateAllow
type:SNTRuleTypeCertificate
customMsg:@""],
[[SNTRule alloc] initWithShasum:@"7846698e47ef41be80b83fb9e2b98fa6dc46c9188b068bff323c302955a00142"
state:SNTRuleStateBlacklist
state:SNTRuleStateBlock
type:SNTRuleTypeCertificate
customMsg:@"Hi There"],
];

View File

@@ -1 +1 @@
{"whitelist_regex": null, "client_mode": "MONITOR", "blacklist_regex": null, "batch_size": 100}
{"allowed_path_regex": null, "client_mode": "MONITOR", "blocked_path_regex": null, "batch_size": 100}

View File

@@ -1 +1 @@
{"whitelist_regex": null, "client_mode": "LOCKDOWN", "blacklist_regex": null, "batch_size": 100}
{"whitelist_regex": null, "client_mode": "LOCKDOWN", "blacklist_regex": null, "batch_size": 100}

View File

@@ -1 +1 @@
{"rules": [{"rule_type": "BINARY", "policy": "BLACKLIST", "sha256": "ee382e199f7eda58863a93a7854b930ade35798bc6856ee8e6ab6ce9277f0eab", "custom_msg": ""},{"rule_type": "CERTIFICATE", "policy": "WHITELIST", "sha256": "46f8c706d0533a54554af5fc163eea704f10c08b30f8a5db12bfdc04fb382fc3", "custom_msg": ""}],"cursor": "this-is-a-cursor="}
{"rules": [{"rule_type": "BINARY", "policy": "BLOCKLIST", "sha256": "ee382e199f7eda58863a93a7854b930ade35798bc6856ee8e6ab6ce9277f0eab", "custom_msg": ""},{"rule_type": "CERTIFICATE", "policy": "ALLOWLIST", "sha256": "46f8c706d0533a54554af5fc163eea704f10c08b30f8a5db12bfdc04fb382fc3", "custom_msg": ""}],"cursor": "this-is-a-cursor="}

View File

@@ -16,6 +16,8 @@ objc_library(
"EventProviders/SNTDriverManager.m",
"EventProviders/SNTEndpointSecurityManager.h",
"EventProviders/SNTEndpointSecurityManager.mm",
"EventProviders/SNTCachingEndpointSecurityManager.h",
"EventProviders/SNTCachingEndpointSecurityManager.mm",
"EventProviders/SNTEventProvider.h",
"Logs/SNTEventLog.h",
"Logs/SNTEventLog.m",
@@ -50,6 +52,7 @@ objc_library(
"IOKit",
],
deps = [
"//Source/common:SantaCache",
"//Source/common:SNTBlockMessage",
"//Source/common:SNTCachedDecision",
"//Source/common:SNTCommonEnums",
@@ -78,7 +81,7 @@ macos_bundle(
linkopts = ["-execute"],
minimum_os_version = "10.9",
version = "//:version",
visibility = ["//visibility:public"],
visibility = ["//:santa_package_group"],
deps = [":santad_lib"],
)
@@ -115,6 +118,7 @@ santa_unit_test(
"bsm",
],
deps = [
"//Source/common:SantaCache",
"//Source/common:SNTBlockMessage",
"//Source/common:SNTCachedDecision",
"//Source/common:SNTCommonEnums",

View File

@@ -14,6 +14,8 @@
#import "Source/santad/DataLayer/SNTDatabaseTable.h"
#include <sqlite3.h>
#import "Source/common/SNTLogging.h"
@interface SNTDatabaseTable ()
@@ -27,16 +29,25 @@
self = [super init];
if (self) {
__block BOOL bail = NO;
[db inDatabase:^(FMDatabase *db) {
if (![db goodConnection]) {
if ([db lastErrorCode] == SQLITE_LOCKED) {
LOGW(@"The database '%@' is locked by another process. Aborting.", [db databasePath]);
[db close];
bail = YES;
return;
}
[db close];
[[NSFileManager defaultManager] removeItemAtPath:[db databasePath] error:NULL];
[db open];
}
}];
_dbQ = db;
if (bail) return nil;
_dbQ = db;
[self updateTableSchema];
}
return self;

View File

@@ -56,7 +56,10 @@
NSData *eventData;
NSNumber *idx = [rs objectForColumn:@"idx"];
@try {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
eventData = [NSKeyedArchiver archivedDataWithRootObject:se];
#pragma clang diagnostic pop
[db executeUpdate:@"UPDATE events SET eventdata=? WHERE idx=?", eventData, idx];
} @catch (NSException *exception) {
[db executeUpdate:@"DELETE FROM events WHERE idx=?", idx];
@@ -98,7 +101,10 @@
NSData *eventData;
@try {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
eventData = [NSKeyedArchiver archivedDataWithRootObject:event];
#pragma clang diagnostic pop
} @catch (NSException *exception) {
continue;
}
@@ -158,7 +164,10 @@
SNTStoredEvent *event;
@try {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
event = [NSKeyedUnarchiver unarchiveObjectWithData:eventData];
#pragma clang diagnostic pop
event.idx = event.idx ?: @((uint32_t)[rs intForColumn:@"idx"]);
} @catch (NSException *exception) {
}

View File

@@ -160,7 +160,7 @@ static const NSUInteger kTransitiveRuleExpirationSeconds = 6 * 30 * 24 * 3600;
__block NSUInteger count = 0;
[self inDatabase:^(FMDatabase *db) {
count = [db longForQuery:@"SELECT COUNT(*) FROM rules WHERE state=?",
@(SNTRuleStateWhitelistCompiler)];
@(SNTRuleStateAllowCompiler)];
}];
return count;
}
@@ -169,7 +169,7 @@ static const NSUInteger kTransitiveRuleExpirationSeconds = 6 * 30 * 24 * 3600;
__block NSUInteger count = 0;
[self inDatabase:^(FMDatabase *db) {
count = [db longForQuery:@"SELECT COUNT(*) FROM rules WHERE state=?",
@(SNTRuleStateWhitelistTransitive)];
@(SNTRuleStateAllowTransitive)];
}];
return count;
}
@@ -216,7 +216,7 @@ static const NSUInteger kTransitiveRuleExpirationSeconds = 6 * 30 * 24 * 3600;
// if no existing rule has matched.
if (!rule && [certificateSHA256 isEqual:self.launchdCSInfo.leafCertificate.SHA256]) {
rule = [[SNTRule alloc] initWithShasum:certificateSHA256
state:SNTRuleStateWhitelist
state:SNTRuleStateAllow
type:SNTRuleTypeCertificate
customMsg:nil
timestamp:0];
@@ -278,23 +278,23 @@ static const NSUInteger kTransitiveRuleExpirationSeconds = 6 * 30 * 24 * 3600;
}
- (BOOL)addedRulesShouldFlushDecisionCache:(NSArray *)rules {
// Check for non-plain-whitelist rules first before querying the database.
// Check for non-plain-allowlist rules first before querying the database.
for (SNTRule *rule in rules) {
if (rule.state != SNTRuleStateWhitelist) return YES;
if (rule.state != SNTRuleStateAllow) return YES;
}
// If still here, then all rules in the array are whitelist rules. So now we look for whitelist
// rules where there is a previously existing whitelist compiler rule for the same shasum.
// If still here, then all rules in the array are allowlist rules. So now we look for allowlist
// rules where there is a previously existing allowlist compiler rule for the same shasum.
// If so we find such a rule, then cache should be flushed.
__block BOOL flushDecisionCache = NO;
[self inTransaction:^(FMDatabase *db, BOOL *rollback) {
for (SNTRule *rule in rules) {
// Whitelist certificate rules are ignored
// Allowlist certificate rules are ignored
if (rule.type == SNTRuleTypeCertificate) continue;
if ([db longForQuery:
@"SELECT COUNT(*) FROM rules WHERE shasum=? AND type=? AND state=? LIMIT 1",
rule.shasum, @(SNTRuleTypeBinary), @(SNTRuleStateWhitelistCompiler)] > 0) {
rule.shasum, @(SNTRuleTypeBinary), @(SNTRuleStateAllowCompiler)] > 0) {
flushDecisionCache = YES;
break;
}
@@ -330,7 +330,7 @@ static const NSUInteger kTransitiveRuleExpirationSeconds = 6 * 30 * 24 * 3600;
[self inDatabase:^(FMDatabase *db) {
if (![db executeUpdate:@"DELETE FROM rules WHERE state=? AND timestamp < ?",
@(SNTRuleStateWhitelistTransitive), @(outdatedTimestamp)]) {
@(SNTRuleStateAllowTransitive), @(outdatedTimestamp)]) {
LOGE(@"Could not remove outdated transitive rules");
}
}];

View File

@@ -37,7 +37,7 @@
- (SNTRule *)_exampleBinaryRule {
SNTRule *r = [[SNTRule alloc] init];
r.shasum = @"a";
r.state = SNTRuleStateBlacklist;
r.state = SNTRuleStateBlock;
r.type = SNTRuleTypeBinary;
r.customMsg = @"A rule";
return r;
@@ -46,7 +46,7 @@
- (SNTRule *)_exampleCertRule {
SNTRule *r = [[SNTRule alloc] init];
r.shasum = @"b";
r.state = SNTRuleStateWhitelist;
r.state = SNTRuleStateAllow;
r.type = SNTRuleTypeCertificate;
return r;
}

View File

@@ -0,0 +1,20 @@
/// Copyright 2021 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 <Foundation/Foundation.h>
#include "Source/santad/EventProviders/SNTEndpointSecurityManager.h"
@interface SNTCachingEndpointSecurityManager : SNTEndpointSecurityManager
@end

View File

@@ -0,0 +1,190 @@
/// Copyright 2021 Google Inc. All rights reserved.
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
#import "Source/santad/EventProviders/SNTCachingEndpointSecurityManager.h"
#import "Source/common/SantaCache.h"
#import "Source/common/SNTLogging.h"
#include <atomic>
#include <EndpointSecurity/EndpointSecurity.h>
uint64_t GetCurrentUptime() {
return clock_gettime_nsec_np(CLOCK_MONOTONIC);
}
template<> uint64_t SantaCacheHasher<santa_vnode_id_t>(santa_vnode_id_t const& t) {
return (SantaCacheHasher<uint64_t>(t.fsid) << 1) ^ SantaCacheHasher<uint64_t>(t.fileid);
}
@implementation SNTCachingEndpointSecurityManager {
std::atomic<bool> _compilerPIDs[PID_MAX];
SantaCache<santa_vnode_id_t, uint64_t> *_decisionCache;
}
- (instancetype)init {
self = [super init];
if (self) {
// TODO(rah): Consider splitting into root/non-root cache
_decisionCache = new SantaCache<santa_vnode_id_t, uint64_t>();
}
return self;
}
- (void)dealloc {
if (_decisionCache) delete _decisionCache;
}
- (BOOL)respondFromCache:(es_message_t *)m API_AVAILABLE(macos(10.15)) {
auto vnode_id = [self vnodeIDForFile:m->event.exec.target->executable];
while (true) {
// Check to see if item is in cache
auto return_action = [self checkCache:vnode_id];
// If item was in cache with a valid response, return it.
// If item is in cache but hasn't received a response yet, sleep for a bit.
// If item is not in cache, break out of loop and forward request to callback.
if (RESPONSE_VALID(return_action)) {
if (return_action == ACTION_RESPOND_ALLOW) {
es_respond_auth_result(self.client, m, ES_AUTH_RESULT_ALLOW, true);
} else {
es_respond_auth_result(self.client, m, ES_AUTH_RESULT_DENY, false);
}
return YES;
} else if (return_action == ACTION_REQUEST_BINARY || return_action == ACTION_RESPOND_ACK) {
// TODO(rah): Look at a replacement for msleep(), maybe NSCondition
usleep(5000);
} else {
break;
}
}
[self addToCache:vnode_id decision:ACTION_REQUEST_BINARY timeout:0];
return NO;
}
- (int)postAction:(santa_action_t)action forMessage:(santa_message_t)sm
API_AVAILABLE(macos(10.15)) {
es_respond_result_t ret;
switch (action) {
case ACTION_RESPOND_ALLOW_COMPILER:
if (sm.pid >= PID_MAX) {
LOGE(@"Unable to watch compiler pid=%d >= pid_max=%d", sm.pid, PID_MAX);
} else {
LOGD(@"Watching compiler pid=%d path=%s", sm.pid, sm.path);
self->_compilerPIDs[sm.pid].store(true);
}
// Allow the exec, but don't cache the decision so subsequent execs of the compiler get
// marked appropriately.
ret = es_respond_auth_result(self.client, (es_message_t *)sm.es_message,
ES_AUTH_RESULT_ALLOW, false);
break;
case ACTION_RESPOND_ALLOW:
case ACTION_RESPOND_ALLOW_PENDING_TRANSITIVE:
[self addToCache:sm.vnode_id decision:ACTION_RESPOND_ALLOW timeout:GetCurrentUptime()];
ret = es_respond_auth_result(self.client, (es_message_t *)sm.es_message,
ES_AUTH_RESULT_ALLOW, true);
break;
case ACTION_RESPOND_DENY:
case ACTION_RESPOND_TOOLONG:
ret = es_respond_auth_result(self.client, (es_message_t *)sm.es_message,
ES_AUTH_RESULT_DENY, false);
break;
case ACTION_RESPOND_ACK:
return ES_RESPOND_RESULT_SUCCESS;
default:
ret = ES_RESPOND_RESULT_ERR_INVALID_ARGUMENT;
}
return ret;
}
- (void)addToCache:(santa_vnode_id_t)identifier
decision:(santa_action_t)decision
timeout:(uint64_t)microsecs {
switch (decision) {
case ACTION_REQUEST_BINARY:
_decisionCache->set(identifier, (uint64_t)ACTION_REQUEST_BINARY << 56, 0);
break;
case ACTION_RESPOND_ACK:
_decisionCache->set(identifier, (uint64_t)ACTION_RESPOND_ACK << 56,
((uint64_t)ACTION_REQUEST_BINARY << 56));
break;
case ACTION_RESPOND_ALLOW:
case ACTION_RESPOND_ALLOW_COMPILER:
case ACTION_RESPOND_DENY: {
// Decision is stored in upper 8 bits, timestamp in remaining 56.
uint64_t val = ((uint64_t)decision << 56) | (microsecs & 0xFFFFFFFFFFFFFF);
if (!_decisionCache->set(identifier, val, ((uint64_t)ACTION_REQUEST_BINARY << 56))) {
_decisionCache->set(identifier, val, ((uint64_t)ACTION_RESPOND_ACK << 56));
}
break;
}
case ACTION_RESPOND_ALLOW_PENDING_TRANSITIVE: {
// Decision is stored in upper 8 bits, timestamp in remaining 56.
uint64_t val = ((uint64_t)decision << 56) | (microsecs & 0xFFFFFFFFFFFFFF);
_decisionCache->set(identifier, val, 0);
break;
}
default:
break;
}
// TODO(rah): Look at a replacement for wakeup(), maybe NSCondition
}
- (BOOL)flushCacheNonRootOnly:(BOOL)nonRootOnly API_AVAILABLE(macos(10.15)) {
_decisionCache->clear();
if (!self.connectionEstablished) return YES; // if not connected, there's nothing to flush.
return es_clear_cache(self.client) == ES_CLEAR_CACHE_RESULT_SUCCESS;
}
- (NSArray<NSNumber *> *)cacheCounts {
return @[@(_decisionCache->count()), @(0)];
}
- (NSArray<NSNumber *> *)cacheBucketCount {
// TODO: add this, maybe.
return nil;
}
- (santa_action_t)checkCache:(santa_vnode_id_t)vnodeID {
auto result = ACTION_UNSET;
uint64_t decision_time = 0;
uint64_t cache_val = _decisionCache->get(vnodeID);
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)) {
if (result == ACTION_RESPOND_DENY) {
auto expiry_time = decision_time + (500 * 100000); // kMaxCacheDenyTimeMilliseconds
if (expiry_time < GetCurrentUptime()) {
_decisionCache->remove(vnodeID);
return ACTION_UNSET;
}
}
}
return result;
}
- (kern_return_t)removeCacheEntryForVnodeID:(santa_vnode_id_t)vnodeID {
_decisionCache->remove(vnodeID);
// TODO(rah): Look at a replacement for wakeup(), maybe NSCondition
return 0;
}
@end

View File

@@ -17,5 +17,14 @@
#include "Source/common/SNTKernelCommon.h"
#include "Source/santad/EventProviders/SNTEventProvider.h"
#include <EndpointSecurity/EndpointSecurity.h>
// Gleaned from https://opensource.apple.com/source/xnu/xnu-4903.241.1/bsd/sys/proc_internal.h
const pid_t PID_MAX = 99999;
@interface SNTEndpointSecurityManager : NSObject<SNTEventProvider>
- (santa_vnode_id_t)vnodeIDForFile:(es_file_t *)file;
@property(readonly, nonatomic) es_client_t *client;
@end

View File

@@ -16,20 +16,17 @@
#include "Source/common/SNTPrefixTree.h"
#import "Source/common/SantaCache.h"
#import "Source/common/SNTConfigurator.h"
#import "Source/common/SNTLogging.h"
#include <EndpointSecurity/EndpointSecurity.h>
#include <atomic>
#include <bsm/libbsm.h>
#include <libproc.h>
#include <atomic>
// Gleaned from https://opensource.apple.com/source/xnu/xnu-4903.241.1/bsd/sys/proc_internal.h
#define PID_MAX 99999
@interface SNTEndpointSecurityManager ()
@property(nonatomic) es_client_t *client;
@property(nonatomic) SNTPrefixTree *prefixTree;
@property(nonatomic, copy) void (^decisionCallback)(santa_message_t);
@property(nonatomic, copy) void (^logCallback)(santa_message_t);
@@ -72,12 +69,27 @@
- (void)establishClient API_AVAILABLE(macos(10.15)) {
while (!self.client) {
SNTConfigurator *config = [SNTConfigurator configurator];
es_client_t *client = NULL;
es_new_client_result_t ret = es_new_client(&client, ^(es_client_t *c, const es_message_t *m) {
pid_t pid = audit_token_to_pid(m->process->audit_token);
int pidversion = audit_token_to_pidversion(m->process->audit_token);
// If enabled, skip any action generated from another endpoint security client.
if (m->process->is_es_client && config.ignoreOtherEndpointSecurityClients) {
if (m->action_type == ES_ACTION_TYPE_AUTH) {
es_respond_auth_result(self.client, m, ES_AUTH_RESULT_ALLOW, false);
}
if (self.selfPID != pid) {
LOGD(@"Skipping event type: 0x%x from es_client pid: %d", m->event_type, pid);
}
return;
}
// Perform the following checks on this serial queue.
// Some checks are simple filters that avoid copying m.
// However, the bulk of the work done here is to support transitive whitelisting.
pid_t pid = audit_token_to_pid(m->process->audit_token);
switch (m->event_type) {
case ES_EVENT_TYPE_NOTIFY_EXEC: {
// Deny results are currently logged when ES_EVENT_TYPE_AUTH_EXEC posts a deny.
@@ -91,6 +103,9 @@
// Ignore unmodified files
if (!m->event.close.modified) return;
// Remove from decision cache in case this is invalidating a cached binary.
[self removeCacheEntryForVnodeID:[self vnodeIDForFile:m->event.close.target]];
// Create a transitive rule if the file was modified by a running compiler
if (pid && pid < PID_MAX && self->_compilerPIDs[pid].load()) {
santa_message_t sm = {};
@@ -104,6 +119,7 @@
}
sm.action = ACTION_NOTIFY_WHITELIST;
sm.pid = pid;
sm.pidversion = pidversion;
LOGI(@"CLOSE: creating a transitive rule: path=%s pid=%d", sm.path, sm.pid);
self.decisionCallback(sm);
}
@@ -125,6 +141,7 @@
}
sm.action = ACTION_NOTIFY_WHITELIST;
sm.pid = pid;
sm.pidversion = pidversion;
LOGI(@"RENAME: creating a transitive rule: path=%s pid=%d", sm.path, sm.pid);
self.decisionCallback(sm);
}
@@ -136,7 +153,35 @@
// Update the set of running compiler PIDs
if (pid && pid < PID_MAX) self->_compilerPIDs[pid].store(false);
// Do not log exits
// Skip the standard pipeline and just log.
if (![config enableForkAndExitLogging]) return;
santa_message_t sm = {};
sm.action = ACTION_NOTIFY_EXIT;
sm.pid = pid;
sm.pidversion = pidversion;
sm.ppid = m->process->original_ppid;
audit_token_t at = m->process->audit_token;
sm.uid = audit_token_to_ruid(at);
sm.gid = audit_token_to_rgid(at);
dispatch_async(self.esNotifyQueue, ^{
self.logCallback(sm);
});
return;
}
case ES_EVENT_TYPE_NOTIFY_FORK: {
// Skip the standard pipeline and just log.
if (![config enableForkAndExitLogging]) return;
santa_message_t sm = {};
sm.action = ACTION_NOTIFY_FORK;
sm.ppid = m->event.fork.child->original_ppid;
audit_token_t at = m->event.fork.child->audit_token;
sm.pid = audit_token_to_pid(at);
sm.pidversion = audit_token_to_pidversion(at);
sm.uid = audit_token_to_ruid(at);
sm.gid = audit_token_to_rgid(at);
dispatch_async(self.esNotifyQueue, ^{
self.logCallback(sm);
});
return;
}
default: {
@@ -190,7 +235,7 @@
switch (ret) {
case ES_NEW_CLIENT_RESULT_SUCCESS:
LOGI(@"Connected to EndpointSecurity");
self.client = client;
_client = client;
return;
case ES_NEW_CLIENT_RESULT_ERR_NOT_PERMITTED:
LOGE(@"Unable to create EndpointSecurity client, not full-disk access permitted");
@@ -205,6 +250,10 @@
}
}
- (BOOL)respondFromCache:(es_message_t *)m API_AVAILABLE(macos(10.15)) {
return NO;
}
- (void)messageHandler:(es_message_t *)m API_AVAILABLE(macos(10.15)) {
santa_message_t sm = {};
sm.es_message = (void *)m;
@@ -215,6 +264,10 @@
switch (m->event_type) {
case ES_EVENT_TYPE_AUTH_EXEC: {
if ([self respondFromCache:m]) {
return;
}
sm.action = ACTION_REQUEST_BINARY;
targetFile = m->event.exec.target->executable;
targetProcess = m->event.exec.target;
@@ -240,6 +293,50 @@
callback = self.logCallback;
break;
}
case ES_EVENT_TYPE_AUTH_UNLINK: {
es_string_token_t pathToken = m->event.unlink.target->path;
NSString *path = [[NSString alloc] initWithBytes:pathToken.data
length:pathToken.length
encoding:NSUTF8StringEncoding];
if (([path isEqualToString:@"/private/var/db/santa/rules.db"] ||
[path isEqualToString:@"/private/var/db/santa/events.db"]) &&
audit_token_to_pid(m->process->audit_token) != self.selfPID) {
LOGW(@"Preventing attempt to delete Santa databases!");
es_respond_auth_result(self.client, m, ES_AUTH_RESULT_DENY, true);
return;
}
es_respond_auth_result(self.client, m, ES_AUTH_RESULT_ALLOW, true);
return;
}
case ES_EVENT_TYPE_AUTH_RENAME: {
es_string_token_t pathToken = m->event.rename.source->path;
NSString *path = [[NSString alloc] initWithBytes:pathToken.data
length:pathToken.length
encoding:NSUTF8StringEncoding];
if (([path isEqualToString:@"/private/var/db/santa/rules.db"] ||
[path isEqualToString:@"/private/var/db/santa/events.db"]) &&
audit_token_to_pid(m->process->audit_token) != self.selfPID) {
LOGW(@"Preventing attempt to rename Santa databases!");
es_respond_auth_result(self.client, m, ES_AUTH_RESULT_DENY, true);
return;
}
es_respond_auth_result(self.client, m, ES_AUTH_RESULT_ALLOW, true);
return;
}
case ES_EVENT_TYPE_AUTH_KEXTLOAD: {
es_string_token_t identifier = m->event.kextload.identifier;
NSString *ident = [[NSString alloc] initWithBytes:identifier.data
length:identifier.length
encoding:NSUTF8StringEncoding];
if ([ident isEqualToString:@"com.google.santa-driver"]) {
LOGW(@"Preventing attempt to load Santa kext!");
es_respond_auth_result(self.client, m, ES_AUTH_RESULT_DENY, true);
return;
}
es_respond_auth_result(self.client, m, ES_AUTH_RESULT_ALLOW, true);
return;
}
case ES_EVENT_TYPE_NOTIFY_CLOSE: {
sm.action = ACTION_NOTIFY_WRITE;
targetFile = m->event.close.target;
@@ -302,6 +399,7 @@
sm.uid = audit_token_to_ruid(targetProcess->audit_token);
sm.gid = audit_token_to_rgid(targetProcess->audit_token);
sm.pid = audit_token_to_pid(targetProcess->audit_token);
sm.pidversion = audit_token_to_pidversion(targetProcess->audit_token);
sm.ppid = targetProcess->original_ppid;
proc_name((m->event_type == ES_EVENT_TYPE_AUTH_EXEC) ? sm.ppid : sm.pid, sm.pname, 1024);
callback(sm);
@@ -311,9 +409,18 @@
while (!self.connectionEstablished) usleep(100000); // 100ms
self.decisionCallback = callback;
es_event_type_t events[] = { ES_EVENT_TYPE_AUTH_EXEC, ES_EVENT_TYPE_NOTIFY_EXIT };
es_return_t sret = es_subscribe(self.client, events, 2);
if (sret != ES_RETURN_SUCCESS) LOGE(@"Unable to subscribe ES_EVENT_TYPE_AUTH_EXEC: %d", sret);
es_event_type_t events[] = {
ES_EVENT_TYPE_AUTH_EXEC,
ES_EVENT_TYPE_AUTH_UNLINK,
ES_EVENT_TYPE_AUTH_RENAME,
ES_EVENT_TYPE_AUTH_KEXTLOAD,
// This is in the decision callback because it's used for detecting
// the exit of a 'compiler' used by transitive whitelisting.
ES_EVENT_TYPE_NOTIFY_EXIT,
};
es_return_t sret = es_subscribe(self.client, events, sizeof(events) / sizeof(es_event_type_t));
if (sret != ES_RETURN_SUCCESS) LOGE(@"Unable to subscribe to auth events: %d", sret);
// There's a gap between creating a client and subscribing to events. Creating the client
// triggers a cache flush automatically but any events that happen in this gap could be allowed
@@ -331,9 +438,10 @@
ES_EVENT_TYPE_NOTIFY_LINK,
ES_EVENT_TYPE_NOTIFY_RENAME,
ES_EVENT_TYPE_NOTIFY_UNLINK,
ES_EVENT_TYPE_NOTIFY_FORK,
};
es_return_t sret = es_subscribe(self.client, events, sizeof(events) / sizeof(es_event_type_t));
if (sret != ES_RETURN_SUCCESS) LOGE(@"Unable to subscribe ES_EVENT_TYPE_NOTIFY_EXEC: %d", sret);
if (sret != ES_RETURN_SUCCESS) LOGE(@"Unable to subscribe to notify events: %d", sret);
}
- (int)postAction:(santa_action_t)action forMessage:(santa_message_t)sm
@@ -452,4 +560,11 @@
return truncated;
}
- (santa_vnode_id_t)vnodeIDForFile:(es_file_t *)file {
return {
.fsid = (uint64_t)file->stat.st_dev,
.fileid = file->stat.st_ino,
};
}
@end

View File

@@ -30,6 +30,8 @@
- (void)logDeniedExecution:(SNTCachedDecision *)cd withMessage:(santa_message_t)message;
- (void)logAllowedExecution:(santa_message_t)message;
- (void)logBundleHashingEvents:(NSArray<SNTStoredEvent *> *)events;
- (void)logFork:(santa_message_t)message;
- (void)logExit:(santa_message_t)message;
- (void)writeLog:(NSString *)log;
// Methods for storing, retrieving, and removing cached decisions.

View File

@@ -82,6 +82,13 @@
[self doesNotRecognizeSelector:_cmd];
}
- (void)logFork:(santa_message_t)message {
[self doesNotRecognizeSelector:_cmd];
}
- (void)logExit:(santa_message_t)message {
[self doesNotRecognizeSelector:_cmd];
}
- (void)writeLog:(NSString *)log {
[self doesNotRecognizeSelector:_cmd];
}
@@ -106,7 +113,7 @@
});
}
// Whenever a cached decision resulting from a transitive whitelist rule is used to allow the
// Whenever a cached decision resulting from a transitive allowlist rule is used to allow the
// execution of a binary, we update the timestamp on the transitive rule in the rules database.
// To prevent writing to the database too often, we space out consecutive writes by 3600 seconds.
- (void)resetTimestampForCachedDecision:(SNTCachedDecision *)cd {
@@ -114,7 +121,7 @@
NSDate *lastUpdate = [self.timestampResetMap objectForKey:cd.sha256];
if (!lastUpdate || -[lastUpdate timeIntervalSinceNow] > 3600) {
SNTRule *rule = [[SNTRule alloc] initWithShasum:cd.sha256
state:SNTRuleStateWhitelistTransitive
state:SNTRuleStateAllowTransitive
type:SNTRuleTypeBinary
customMsg:nil];
[[SNTDatabaseController ruleTable] resetTimestampForRule:rule];

View File

@@ -65,8 +65,8 @@
char ppath[PATH_MAX] = "(null)";
proc_pidpath(message.pid, ppath, PATH_MAX);
[outStr appendFormat:@"|pid=%d|ppid=%d|process=%s|processpath=%s|uid=%d|user=%@|gid=%d|group=%@",
message.pid, message.ppid, message.pname, ppath,
[outStr appendFormat:@"|pid=%d|pidversion=%d|ppid=%d|process=%s|processpath=%s|uid=%d|user=%@|gid=%d|group=%@",
message.pid, message.pidversion, message.ppid, message.pname, ppath,
message.uid, [self nameForUID:message.uid],
message.gid, [self nameForGID:message.gid]];
@@ -169,8 +169,8 @@
mode = @"U"; break;
}
[outLog appendFormat:@"|pid=%d|ppid=%d|uid=%d|user=%@|gid=%d|group=%@|mode=%@|path=%@",
message.pid, message.ppid,
[outLog appendFormat:@"|pid=%d|pidversion=%d|ppid=%d|uid=%d|user=%@|gid=%d|group=%@|mode=%@|path=%@",
message.pid, message.pidversion, message.ppid,
message.uid, [self nameForUID:message.uid],
message.gid, [self nameForGID:message.gid],
mode, [self sanitizeString:@(message.path)]];
@@ -268,6 +268,19 @@
}
}
- (void)logFork:(santa_message_t)message {
NSString *s = [NSString stringWithFormat:@"action=FORK|pid=%d|pidversion=%d|ppid=%d|uid=%d|gid=%d",
message.pid, message.pidversion, message.ppid, message.uid, message.gid];
[self writeLog:s];
}
- (void)logExit:(santa_message_t)message {
NSString *s = [NSString stringWithFormat:@"action=EXIT|pid=%d|pidversion=%d|ppid=%d|uid=%d|gid=%d",
message.pid, message.pidversion, message.ppid, message.uid, message.gid];
[self writeLog:s];
}
- (void)writeLog:(NSString *)log {
LOGI(@"%@", log);
}

View File

@@ -33,6 +33,7 @@
#import "Source/santad/DataLayer/SNTRuleTable.h"
#import "Source/santad/DataLayer/SNTEventTable.h"
#import "Source/santad/EventProviders/SNTDriverManager.h"
#import "Source/santad/EventProviders/SNTCachingEndpointSecurityManager.h"
#import "Source/santad/EventProviders/SNTEndpointSecurityManager.h"
#import "Source/santad/EventProviders/SNTEventProvider.h"
#import "Source/santad/Logs/SNTFileEventLog.h"
@@ -59,8 +60,13 @@
// Choose an event logger.
// Locate and connect to driver / SystemExtension
if ([configurator enableSystemExtension]) {
LOGI(@"Using EndpointSecurity as event provider.");
_eventProvider = [[SNTEndpointSecurityManager alloc] init];
if ([configurator enableSysxCache]) {
LOGI(@"Using CachingEndpointSecurity as event provider.");
_eventProvider = [[SNTCachingEndpointSecurityManager alloc] init];
} else {
LOGI(@"Using EndpointSecurity as event provider.");
_eventProvider = [[SNTEndpointSecurityManager alloc] init];
}
} else {
LOGI(@"Using Kauth as event provider.");
_eventProvider = [[SNTDriverManager alloc] init];
@@ -121,11 +127,11 @@
options:bits
context:NULL];
[configurator addObserver:self
forKeyPath:NSStringFromSelector(@selector(whitelistPathRegex))
forKeyPath:NSStringFromSelector(@selector(allowedPathRegex))
options:bits
context:NULL];
[configurator addObserver:self
forKeyPath:NSStringFromSelector(@selector(blacklistPathRegex))
forKeyPath:NSStringFromSelector(@selector(blockedPathRegex))
options:bits
context:NULL];
if (![configurator enableSystemExtension]) {
@@ -222,6 +228,12 @@
[self->_eventLog logAllowedExecution:message];
break;
}
case ACTION_NOTIFY_FORK:
[self->_eventLog logFork:message];
break;
case ACTION_NOTIFY_EXIT:
[self->_eventLog logExit:message];
break;
default:
LOGE(@"Received log request without a valid action: %d", message.action);
break;
@@ -309,15 +321,15 @@ void diskDisappearedCallback(DADiskRef disk, void *context) {
NSURL *old = [change[oldKey] isKindOfClass:[NSURL class]] ? change[oldKey] : nil;
if (!new && !old) return;
if (![new.absoluteString isEqualToString:old.absoluteString]) [self syncBaseURLDidChange:new];
} else if ([keyPath isEqualToString:NSStringFromSelector(@selector(whitelistPathRegex))] ||
[keyPath isEqualToString:NSStringFromSelector(@selector(blacklistPathRegex))]) {
} else if ([keyPath isEqualToString:NSStringFromSelector(@selector(allowedPathRegex))] ||
[keyPath isEqualToString:NSStringFromSelector(@selector(blockedPathRegex))]) {
NSRegularExpression *new =
[change[newKey] isKindOfClass:[NSRegularExpression class]] ? change[newKey] : nil;
NSRegularExpression *old =
[change[oldKey] isKindOfClass:[NSRegularExpression class]] ? change[oldKey] : nil;
if (!new && !old) return;
if (![new.pattern isEqualToString:old.pattern]) {
LOGI(@"Changed [white|black]list regex, flushing cache");
LOGI(@"Changed [allow|deny]list regex, flushing cache");
[self.eventProvider flushCacheNonRootOnly:NO];
}
} else if ([keyPath isEqualToString:NSStringFromSelector(@selector(enableSystemExtension))]) {
@@ -325,11 +337,6 @@ void diskDisappearedCallback(DADiskRef disk, void *context) {
BOOL old = [change[oldKey] isKindOfClass:[NSNumber class]] ? [change[oldKey] boolValue] : NO;
if (old == NO && new == YES) {
LOGI(@"EnableSystemExtension changed NO -> YES");
NSTask *t = [[NSTask alloc] init];
t.launchPath = [@(kSantaAppPath) stringByAppendingString:@"/Contents/MacOS/Santa"];
t.arguments = @[ @"--load-system-extension" ];
[t launch];
[t waitUntilExit];
LOGI(@"The penultimate exit.");
exit(0);
}

View File

@@ -58,7 +58,7 @@
}
// Assume that this method is called only when we already know that the writing process is a
// compiler. It checks if the closed file is executable, and if so, transitively whitelists it.
// compiler. It checks if the closed file is executable, and if so, transitively allowlists it.
// The passed in message contains the pid of the writing process and path of closed file.
- (void)createTransitiveRule:(santa_message_t)message {
[self saveFakeDecision:message];
@@ -69,13 +69,13 @@
SNTFileInfo *fi = [[SNTFileInfo alloc] initWithPath:@(target)];
if (fi.isExecutable) {
// Check if there is an existing (non-transitive) rule for this file. We leave existing rules
// alone, so that a whitelist or blacklist rule can't be overwritten by a transitive one.
// alone, so that a allowlist or blocklist rule can't be overwritten by a transitive one.
SNTRuleTable *ruleTable = [SNTDatabaseController ruleTable];
SNTRule *prevRule = [ruleTable ruleForBinarySHA256:fi.SHA256 certificateSHA256:nil];
if (!prevRule || prevRule.state == SNTRuleStateWhitelistTransitive) {
// Construct a new transitive whitelist rule for the executable.
if (!prevRule || prevRule.state == SNTRuleStateAllowTransitive) {
// Construct a new transitive allowlist rule for the executable.
SNTRule *rule = [[SNTRule alloc] initWithShasum:fi.SHA256
state:SNTRuleStateWhitelistTransitive
state:SNTRuleStateAllowTransitive
type:SNTRuleTypeBinary
customMsg:@""];
@@ -85,8 +85,8 @@
LOGE(@"unable to add new transitive rule to database: %@", err.localizedDescription);
} else {
[self.eventLog
writeLog:[NSString stringWithFormat:@"action=WHITELIST|pid=%d|path=%s|sha256=%@",
message.pid, target, fi.SHA256]];
writeLog:[NSString stringWithFormat:@"action=ALLOWLIST|pid=%d|pidversion=%d|path=%s|sha256=%@",
message.pid, message.pidversion, target, fi.SHA256]];
}
}
}

View File

@@ -107,9 +107,9 @@ double watchdogRAMPeak = 0;
reply:(void (^)(NSError *error))reply {
SNTRuleTable *ruleTable = [SNTDatabaseController ruleTable];
// If any rules are added that are not plain whitelist rules, then flush decision cache.
// In particular, the addition of whitelist compiler rules should cause a cache flush.
// We also flush cache if a whitelist compiler rule is replaced with a whitelist rule.
// If any rules are added that are not plain allowlist rules, then flush decision cache.
// In particular, the addition of allowlist compiler rules should cause a cache flush.
// We also flush cache if a allowlist compiler rule is replaced with a allowlist rule.
BOOL flushCache = (cleanSlate || [ruleTable addedRulesShouldFlushDecisionCache:rules]);
NSError *error;
@@ -153,7 +153,8 @@ double watchdogRAMPeak = 0;
certificateSHA256:(NSString *)certificateSHA256
reply:(void (^)(SNTEventState))reply {
reply([self.policyProcessor decisionForFilePath:filePath
fileSHA256:fileSHA256].decision);
fileSHA256:fileSHA256
certificateSHA256:certificateSHA256].decision);
}
#pragma mark Config Ops
@@ -207,19 +208,19 @@ double watchdogRAMPeak = 0;
reply();
}
- (void)setWhitelistPathRegex:(NSString *)pattern reply:(void (^)(void))reply {
- (void)setAllowedPathRegex:(NSString *)pattern reply:(void (^)(void))reply {
NSRegularExpression *re = [NSRegularExpression regularExpressionWithPattern:pattern
options:0
error:NULL];
[[SNTConfigurator configurator] setSyncServerWhitelistPathRegex:re];
[[SNTConfigurator configurator] setSyncServerAllowedPathRegex:re];
reply();
}
- (void)setBlacklistPathRegex:(NSString *)pattern reply:(void (^)(void))reply {
- (void)setBlockedPathRegex:(NSString *)pattern reply:(void (^)(void))reply {
NSRegularExpression *re = [NSRegularExpression regularExpressionWithPattern:pattern
options:0
error:NULL];
[[SNTConfigurator configurator] setSyncServerBlacklistPathRegex:re];
[[SNTConfigurator configurator] setSyncServerBlockedPathRegex:re];
reply();
}
@@ -232,12 +233,12 @@ double watchdogRAMPeak = 0;
reply();
}
- (void)enableTransitiveWhitelisting:(void (^)(BOOL))reply {
reply([SNTConfigurator configurator].enableTransitiveWhitelisting);
- (void)enableTransitiveRules:(void (^)(BOOL))reply {
reply([SNTConfigurator configurator].enableTransitiveRules);
}
- (void)setEnableTransitiveWhitelisting:(BOOL)enabled reply:(void (^)(void))reply {
[[SNTConfigurator configurator] setEnableTransitiveWhitelisting:enabled];
- (void)setEnableTransitiveRules:(BOOL)enabled reply:(void (^)(void))reply {
[[SNTConfigurator configurator] setEnableTransitiveRules:enabled];
reply();
}

View File

@@ -98,12 +98,12 @@
[super tearDown];
}
- (void)testBinaryWhitelistRule {
- (void)testBinaryAllowRule {
OCMStub([self.mockFileInfo isMachO]).andReturn(YES);
OCMStub([self.mockFileInfo SHA256]).andReturn(@"a");
SNTRule *rule = [[SNTRule alloc] init];
rule.state = SNTRuleStateWhitelist;
rule.state = SNTRuleStateAllow;
rule.type = SNTRuleTypeBinary;
OCMStub([self.mockRuleDatabase ruleForBinarySHA256:@"a" certificateSHA256:nil]).andReturn(rule);
@@ -112,12 +112,12 @@
OCMVerify([self.mockDriverManager postAction:ACTION_RESPOND_ALLOW forMessage:[self getMessage]]);
}
- (void)testBinaryBlacklistRule {
- (void)testBinaryBlockRule {
OCMStub([self.mockFileInfo isMachO]).andReturn(YES);
OCMStub([self.mockFileInfo SHA256]).andReturn(@"a");
SNTRule *rule = [[SNTRule alloc] init];
rule.state = SNTRuleStateBlacklist;
rule.state = SNTRuleStateBlock;
rule.type = SNTRuleTypeBinary;
OCMStub([self.mockRuleDatabase ruleForBinarySHA256:@"a" certificateSHA256:nil]).andReturn(rule);
@@ -127,7 +127,7 @@
}
- (void)testCertificateWhitelistRule {
- (void)testCertificateAllowRule {
OCMStub([self.mockFileInfo isMachO]).andReturn(YES);
id cert = OCMClassMock([MOLCertificate class]);
@@ -135,7 +135,7 @@
OCMStub([cert SHA256]).andReturn(@"a");
SNTRule *rule = [[SNTRule alloc] init];
rule.state = SNTRuleStateWhitelist;
rule.state = SNTRuleStateAllow;
rule.type = SNTRuleTypeCertificate;
OCMStub([self.mockRuleDatabase ruleForBinarySHA256:nil certificateSHA256:@"a"]).andReturn(rule);
@@ -144,7 +144,7 @@
OCMVerify([self.mockDriverManager postAction:ACTION_RESPOND_ALLOW forMessage:[self getMessage]]);
}
- (void)testCertificateBlacklistRule {
- (void)testCertificateBlockRule {
OCMStub([self.mockFileInfo isMachO]).andReturn(YES);
id cert = OCMClassMock([MOLCertificate class]);
@@ -152,7 +152,7 @@
OCMStub([cert SHA256]).andReturn(@"a");
SNTRule *rule = [[SNTRule alloc] init];
rule.state = SNTRuleStateBlacklist;
rule.state = SNTRuleStateBlock;
rule.type = SNTRuleTypeCertificate;
OCMStub([self.mockRuleDatabase ruleForBinarySHA256:nil certificateSHA256:@"a"]).andReturn(rule);
@@ -161,13 +161,13 @@
OCMVerify([self.mockDriverManager postAction:ACTION_RESPOND_DENY forMessage:[self getMessage]]);
}
- (void)testBinaryWhitelistCompilerRule {
- (void)testBinaryAllowCompilerRule {
OCMStub([self.mockFileInfo isMachO]).andReturn(YES);
OCMStub([self.mockFileInfo SHA256]).andReturn(@"a");
OCMStub([self.mockConfigurator enableTransitiveWhitelisting]).andReturn(YES);
OCMStub([self.mockConfigurator enableTransitiveRules]).andReturn(YES);
SNTRule *rule = [[SNTRule alloc] init];
rule.state = SNTRuleStateWhitelistCompiler;
rule.state = SNTRuleStateAllowCompiler;
rule.type = SNTRuleTypeBinary;
OCMStub([self.mockRuleDatabase ruleForBinarySHA256:@"a" certificateSHA256:nil]).andReturn(rule);
@@ -177,13 +177,13 @@
forMessage:[self getMessage]]);
}
- (void)testBinaryWhitelistCompilerRuleDisabled {
- (void)testBinaryAllowCompilerRuleDisabled {
OCMStub([self.mockFileInfo isMachO]).andReturn(YES);
OCMStub([self.mockFileInfo SHA256]).andReturn(@"a");
OCMStub([self.mockConfigurator enableTransitiveWhitelisting]).andReturn(NO);
OCMStub([self.mockConfigurator enableTransitiveRules]).andReturn(NO);
SNTRule *rule = [[SNTRule alloc] init];
rule.state = SNTRuleStateWhitelistCompiler;
rule.state = SNTRuleStateAllowCompiler;
rule.type = SNTRuleTypeBinary;
OCMStub([self.mockRuleDatabase ruleForBinarySHA256:@"a" certificateSHA256:nil]).andReturn(rule);
@@ -192,13 +192,13 @@
OCMVerify([self.mockDriverManager postAction:ACTION_RESPOND_ALLOW forMessage:[self getMessage]]);
}
- (void)testBinaryWhitelistTransitiveRule {
- (void)testBinaryAllowTransitiveRule {
OCMStub([self.mockFileInfo isMachO]).andReturn(YES);
OCMStub([self.mockFileInfo SHA256]).andReturn(@"a");
OCMStub([self.mockConfigurator enableTransitiveWhitelisting]).andReturn(YES);
OCMStub([self.mockConfigurator enableTransitiveRules]).andReturn(YES);
SNTRule *rule = [[SNTRule alloc] init];
rule.state = SNTRuleStateWhitelistTransitive;
rule.state = SNTRuleStateAllowTransitive;
rule.type = SNTRuleTypeBinary;
OCMStub([self.mockRuleDatabase ruleForBinarySHA256:@"a" certificateSHA256:nil]).andReturn(rule);
@@ -207,14 +207,14 @@
OCMVerify([self.mockDriverManager postAction:ACTION_RESPOND_ALLOW forMessage:[self getMessage]]);
}
- (void)testBinaryWhitelistTransitiveRuleDisabled {
- (void)testBinaryAllowTransitiveRuleDisabled {
OCMStub([self.mockFileInfo isMachO]).andReturn(YES);
OCMStub([self.mockFileInfo SHA256]).andReturn(@"a");
OCMStub([self.mockConfigurator clientMode]).andReturn(SNTClientModeLockdown);
OCMStub([self.mockConfigurator enableTransitiveWhitelisting]).andReturn(NO);
OCMStub([self.mockConfigurator enableTransitiveRules]).andReturn(NO);
SNTRule *rule = [[SNTRule alloc] init];
rule.state = SNTRuleStateWhitelistTransitive;
rule.state = SNTRuleStateAllowTransitive;
rule.type = SNTRuleTypeBinary;
OCMStub([self.mockRuleDatabase ruleForBinarySHA256:@"a" certificateSHA256:nil]).andReturn(rule);

View File

@@ -39,11 +39,14 @@
/// @param fileInfo A SNTFileInfo object.
/// @param fileSHA256 The pre-calculated SHA256 hash for the file, can be nil. If nil the hash will
/// be calculated by this method from the filePath.
/// @param certificateSHA256 The pre-calculated SHA256 hash of the leaf certificate. If nil, the
/// signature will be validated on the binary represented by fileInfo.
///
- (nonnull SNTCachedDecision *)decisionForFileInfo:(nonnull SNTFileInfo *)fileInfo
fileSHA256:(nullable NSString *)fileSHA256;
fileSHA256:(nullable NSString *)fileSHA256
certificateSHA256:(nullable NSString *)certificateSHA256;
/// Convenience initializer with a nil hash.
/// Convenience initializer with nil hashes for both the file and certificate.
- (nonnull SNTCachedDecision *)decisionForFileInfo:(nonnull SNTFileInfo *)fileInfo;
///
@@ -53,6 +56,7 @@
/// calculated, use the fileSHA256 parameter to save a second calculation of the hash.
///
- (nonnull SNTCachedDecision *)decisionForFilePath:(nonnull NSString *)filePath
fileSHA256:(nullable NSString *)fileSHA256;
fileSHA256:(nullable NSString *)fileSHA256
certificateSHA256:(nullable NSString *)certificateSHA256;
@end

View File

@@ -39,7 +39,8 @@
}
- (nonnull SNTCachedDecision *)decisionForFileInfo:(nonnull SNTFileInfo *)fileInfo
fileSHA256:(nullable NSString *)fileSHA256 {
fileSHA256:(nullable NSString *)fileSHA256
certificateSHA256:(nullable NSString *)certificateSHA256 {
SNTCachedDecision *cd = [[SNTCachedDecision alloc] init];
cd.sha256 = fileSHA256 ?: fileInfo.SHA256;
@@ -48,19 +49,23 @@
SNTCachedDecision *systemCd = self.ruleTable.criticalSystemBinaries[cd.sha256];
if (systemCd) return systemCd;
// Grab the code signature, if there's an error don't try to capture
// any of the signature details.
NSError *csInfoError;
MOLCodesignChecker *csInfo = [fileInfo codesignCheckerWithError:&csInfoError];
if (csInfoError) {
csInfo = nil;
cd.decisionExtra =
[NSString stringWithFormat:@"Signature ignored due to error: %ld", (long)csInfoError.code];
if (certificateSHA256.length) {
cd.certSHA256 = certificateSHA256;
} else {
// Grab the code signature, if there's an error don't try to capture
// any of the signature details.
MOLCodesignChecker *csInfo = [fileInfo codesignCheckerWithError:&csInfoError];
if (csInfoError) {
csInfo = nil;
cd.decisionExtra =
[NSString stringWithFormat:@"Signature ignored due to error: %ld", (long)csInfoError.code];
} else {
cd.certSHA256 = csInfo.leafCertificate.SHA256;
cd.certCommonName = csInfo.leafCertificate.commonName;
cd.certChain = csInfo.certificates;
}
}
cd.certSHA256 = csInfo.leafCertificate.SHA256;
cd.certCommonName = csInfo.leafCertificate.commonName;
cd.certChain = csInfo.certificates;
cd.quarantineURL = fileInfo.quarantineDataURL;
SNTRule *rule = [self.ruleTable ruleForBinarySHA256:cd.sha256
@@ -69,30 +74,30 @@
switch (rule.type) {
case SNTRuleTypeBinary:
switch (rule.state) {
case SNTRuleStateWhitelist:
case SNTRuleStateAllow:
cd.decision = SNTEventStateAllowBinary;
return cd;
case SNTRuleStateSilentBlacklist:
case SNTRuleStateSilentBlock:
cd.silentBlock = YES;
case SNTRuleStateBlacklist:
case SNTRuleStateBlock:
cd.customMsg = rule.customMsg;
cd.decision = SNTEventStateBlockBinary;
return cd;
case SNTRuleStateWhitelistCompiler:
// If transitive whitelisting is enabled, then SNTRuleStateWhiteListCompiler rules
case SNTRuleStateAllowCompiler:
// If transitive rules are enabled, then SNTRuleStateAllowListCompiler rules
// become SNTEventStateAllowCompiler decisions. Otherwise we treat the rule as if
// it were SNTRuleStateWhitelist.
if ([[SNTConfigurator configurator] enableTransitiveWhitelisting]) {
// it were SNTRuleStateAllow.
if ([[SNTConfigurator configurator] enableTransitiveRules]) {
cd.decision = SNTEventStateAllowCompiler;
} else {
cd.decision = SNTEventStateAllowBinary;
}
return cd;
case SNTRuleStateWhitelistTransitive:
// If transitive whitelisting is enabled, then SNTRuleStateWhitelistTransitive
case SNTRuleStateAllowTransitive:
// If transitive rules are enabled, then SNTRuleStateAllowTransitive
// rules become SNTEventStateAllowTransitive decisions. Otherwise, we treat the
// rule as if it were SNTRuleStateUnknown.
if ([[SNTConfigurator configurator] enableTransitiveWhitelisting]) {
if ([[SNTConfigurator configurator] enableTransitiveRules]) {
cd.decision = SNTEventStateAllowTransitive;
return cd;
} else {
@@ -103,13 +108,13 @@
break;
case SNTRuleTypeCertificate:
switch (rule.state) {
case SNTRuleStateWhitelist:
case SNTRuleStateAllow:
cd.decision = SNTEventStateAllowCertificate;
return cd;
case SNTRuleStateSilentBlacklist:
case SNTRuleStateSilentBlock:
cd.silentBlock = YES;
// intentional fallthrough
case SNTRuleStateBlacklist:
case SNTRuleStateBlock:
cd.customMsg = rule.customMsg;
cd.decision = SNTEventStateBlockCertificate;
return cd;
@@ -129,14 +134,14 @@
return cd;
}
NSString *msg = [self fileIsScopeBlacklisted:fileInfo];
NSString *msg = [self fileIsScopeBlocked:fileInfo];
if (msg) {
cd.decisionExtra = msg;
cd.decision = SNTEventStateBlockScope;
return cd;
}
msg = [self fileIsScopeWhitelisted:fileInfo];
msg = [self fileIsScopeAllowed:fileInfo];
if (msg) {
cd.decisionExtra = msg;
cd.decision = SNTEventStateAllowScope;
@@ -157,16 +162,19 @@
}
- (nonnull SNTCachedDecision *)decisionForFileInfo:(nonnull SNTFileInfo *)fileInfo {
return [self decisionForFileInfo:fileInfo fileSHA256:nil];
return [self decisionForFileInfo:fileInfo fileSHA256:nil certificateSHA256:nil];
}
- (nonnull SNTCachedDecision *)decisionForFilePath:(nonnull NSString *)filePath
fileSHA256:(nullable NSString *)fileSHA256 {
fileSHA256:(nullable NSString *)fileSHA256
certificateSHA256:(nullable NSString *)certificateSHA256 {
SNTFileInfo *fileInfo;
NSError *error;
fileInfo = [[SNTFileInfo alloc] initWithPath:filePath error:&error];
if (!fileInfo) LOGW(@"Failed to read file %@: %@", filePath, error.localizedDescription);
return [self decisionForFileInfo:fileInfo fileSHA256:fileSHA256];
return [self decisionForFileInfo:fileInfo
fileSHA256:fileSHA256
certificateSHA256:certificateSHA256];
}
///
@@ -174,17 +182,17 @@
///
/// Files that are out of scope:
/// + Non Mach-O files that are not part of an installer package.
/// + Files in whitelisted path.
/// + Files in allowed path.
///
/// @return @c YES if file is in scope, @c NO otherwise.
///
- (NSString *)fileIsScopeWhitelisted:(SNTFileInfo *)fi {
- (NSString *)fileIsScopeAllowed:(SNTFileInfo *)fi {
if (!fi) return nil;
// Determine if file is within a whitelisted path
NSRegularExpression *re = [[SNTConfigurator configurator] whitelistPathRegex];
// Determine if file is within an allowed path
NSRegularExpression *re = [[SNTConfigurator configurator] allowedPathRegex];
if ([re numberOfMatchesInString:fi.path options:0 range:NSMakeRange(0, fi.path.length)]) {
return @"Whitelist Regex";
return @"Allowed Path Regex";
}
// If file is not a Mach-O file, we're not interested.
@@ -195,12 +203,12 @@
return nil;
}
- (NSString *)fileIsScopeBlacklisted:(SNTFileInfo *)fi {
- (NSString *)fileIsScopeBlocked:(SNTFileInfo *)fi {
if (!fi) return nil;
NSRegularExpression *re = [[SNTConfigurator configurator] blacklistPathRegex];
NSRegularExpression *re = [[SNTConfigurator configurator] blockedPathRegex];
if ([re numberOfMatchesInString:fi.path options:0 range:NSMakeRange(0, fi.path.length)]) {
return @"Blacklist Regex";
return @"Blocked Path Regex";
}
if ([[SNTConfigurator configurator] enablePageZeroProtection] && fi.isMissingPageZero) {

View File

@@ -96,11 +96,21 @@ void cleanup() {
[fm removeItemAtPath:@"/Library/LaunchDaemons/com.google.santad.plist" error:NULL];
[SNTDriverManager unloadDriver];
[fm removeItemAtPath:@"/Library/Extensions/santa-driver.kext" error:NULL];
LOGI(@"loading com.google.santa.daemon as a SystemExtension");
NSTask *t = [[NSTask alloc] init];
t.launchPath = [@(kSantaAppPath) stringByAppendingString:@"/Contents/MacOS/Santa"];
t.arguments = @[ @"--load-system-extension" ];
[t launch];
[t waitUntilExit];
t = [[NSTask alloc] init];
t.launchPath = @"/bin/launchctl";
t.arguments = @[ @"remove", @"com.google.santad" ];
[t launch];
[t waitUntilExit];
// This exit will likely never be called because the above launchctl command kill us.
exit(0);
}

View File

@@ -0,0 +1,28 @@
load("@build_bazel_rules_apple//apple:macos.bzl", "macos_command_line_application")
licenses(["notice"]) # Apache 2.0
objc_library(
name = "santass_lib",
srcs = [
"SNTSyncService.h",
"SNTSyncService.m",
"main.m",
],
deps = [
"//Source/common:SNTLogging",
"//Source/common:SNTXPCSyncServiceInterface",
"@MOLCodesignChecker",
"@MOLXPCConnection",
],
)
macos_command_line_application(
name = "santasyncservice",
bundle_id = "com.google.santa.syncservice",
infoplists = ["Info.plist"],
minimum_os_version = "10.9",
version = "//:version",
visibility = ["//:santa_package_group"],
deps = [":santass_lib"],
)

View File

@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleDisplayName</key>
<string>santasyncservice</string>
<key>CFBundleExecutable</key>
<string>santasyncservice</string>
<key>CFBundleIdentifier</key>
<string>com.google.santa.syncservice</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>santasyncservice</string>
<key>CFBundleShortVersionString</key>
<string>${SANTA_VERSION}</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>${SANTA_VERSION}</string>
<key>NSHumanReadableCopyright</key>
<string>Google LLC.</string>
</dict>
</plist>

View File

@@ -0,0 +1,20 @@
/// Copyright 2020 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 <Foundation/Foundation.h>
#import "Source/common/SNTXPCSyncServiceInterface.h"
@interface SNTSyncService : NSObject<SNTSyncServiceXPC>
@end

View File

@@ -0,0 +1,29 @@
/// Copyright 2020 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 "SNTSyncService.h"
// TODO(bur): Add "santactl sync --daemon" behavior here.
@implementation SNTSyncService
- (void)postEventsToSyncServer:(NSArray<SNTStoredEvent *> *)events fromBundle:(BOOL)fromBundle {}
- (void)postBundleEventToSyncServer:(SNTStoredEvent *)event
reply:(void (^)(SNTBundleEventAction))reply {}
- (void)isFCMListening:(void (^)(BOOL))reply {}
- (void)performFullSyncWithReply:(SNTFullSyncReplyBlock)reply {}
@end

View File

@@ -0,0 +1,35 @@
/// Copyright 2020 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 <Foundation/Foundation.h>
#import <MOLXPCConnection/MOLXPCConnection.h>
#import "Source/common/SNTLogging.h"
#import "Source/common/SNTXPCSyncServiceInterface.h"
#import "Source/santasyncservice/SNTSyncService.h"
int main(int argc, const char *argv[]) {
@autoreleasepool {
NSDictionary *infoDict = [[NSBundle mainBundle] infoDictionary];
LOGI(@"Started, version %@", infoDict[@"CFBundleVersion"]);
MOLXPCConnection *c =
[[MOLXPCConnection alloc] initServerWithName:[SNTXPCSyncServiceInterface serviceID]];
c.privilegedInterface = c.unprivilegedInterface =
[SNTXPCSyncServiceInterface syncServiceInterface];
c.exportedObject = [[SNTSyncService alloc] init];
[c resume];
[[NSRunLoop mainRunLoop] run];
}
}

View File

@@ -8,7 +8,7 @@ load("@bazel_tools//tools/build_defs/repo:git.bzl",
git_repository(
name = "build_bazel_rules_apple",
remote = "https://github.com/bazelbuild/rules_apple.git",
tag = "0.19.0",
tag = "0.21.2",
)
load("@build_bazel_rules_apple//apple:repositories.bzl", "apple_rules_dependencies")
@@ -19,7 +19,7 @@ apple_rules_dependencies()
git_repository(
name = "MOLAuthenticatingURLSession",
remote = "https://github.com/google/macops-molauthenticatingurlsession.git",
tag = "v2.8",
tag = "v2.9",
)
git_repository(

View File

@@ -1 +1,5 @@
theme: jekyll-theme-cayman
theme: jekyll-theme-cayman
plugins:
- jekyll-redirect-from

View File

@@ -12,9 +12,9 @@ Two configuration methods can be used to control Santa: a local configuration pr
| ----------------------------- | ---------- | ---------------------------------------- |
| ClientMode* | Integer | 1 = MONITOR, 2 = LOCKDOWN, defaults to MONITOR |
| FileChangesRegex* | String | The regex of paths to log file changes. Regexes are specified in ICU format. |
| WhitelistRegex* | String | A regex to whitelist if the binary or certificate scopes did not allow execution. Regexes are specified in ICU format. |
| BlacklistRegex* | String | A regex to blacklist if the binary or certificate scopes did not block an execution. Regexes are specified in ICU format. |
| EnablePageZeroProtection | Bool | Enable `__PAGEZERO` protection, defaults to YES. If this flag is set to YES, 32-bit binaries that are missing the `__PAGEZERO` segment will be blocked even in MONITOR mode, **unless** the binary is whitelisted by an explicit rule. |
| AllowedPathRegex* | String | A regex to allow if the binary or certificate scopes did not allow/block execution. Regexes are specified in ICU format. |
| BlockedPathRegex* | String | A regex to block if the binary or certificate scopes did not allow/block an execution. Regexes are specified in ICU format. |
| EnablePageZeroProtection | Bool | Enable `__PAGEZERO` protection, defaults to YES. If this flag is set to YES, 32-bit binaries that are missing the `__PAGEZERO` segment will be blocked even in MONITOR mode, **unless** the binary is allowed by an explicit rule. |
| MoreInfoURL | String | The URL to open when the user clicks "More Info..." when opening Santa.app. If unset, the button will not be displayed. |
| EventDetailURL | String | See the [EventDetailURL](#eventdetailurl) section below. |
| EventDetailText | String | Related to the above property, this string represents the text to show on the button. |
@@ -52,8 +52,9 @@ This property contains a kind of format string to be turned into the URL to send
| %file_sha% | SHA-256 of the file that was blocked |
| %machine_id% | ID of the machine |
| %username% | The executing user |
| %bundle_id% | Bundle ID of the binary, if applicable |
| %bundle_ver% | Bundle version of the binary, if applicable |
| %serial% | System's serial number |
| %uuid% | System's UUID |
| %hostname% | System's full hostname |
For example: `https://sync-server-hostname/%machine_id%/%file_sha%`
@@ -167,13 +168,14 @@ Configuration profiles have a `.mobileconfig` file extension. There are many way
| clean_sync** | Bool | If set to `True` Santa will clear all local rules and download a fresh copy from the sync-server. Defaults to `False`. |
| batch_size | Integer | The number of rules to download or events to upload per request. Multiple requests will be made if there is more work than can fit in single request. Defaults to 50. |
| upload_logs_url** | String | If set, the endpoint to send Santa's current logs. No default. |
| whitelist_regex | String | Same as the "Local Configuration" WhitelistRegex. No default. |
| blacklist_regex | String | Same as the "Local Configuration" BlacklistRegex. No default. |
| allowed_path_regex | String | Same as the "Local Configuration" AllowedPathRegex. No default. |
| blocked_path_regex | String | Same as the "Local Configuration" BlockedPathRegex. No default. |
| full_sync_interval* | Integer | The max time to wait before performing a full sync with the server. Defaults to 600 secs (10 minutes) if not set. |
| fcm_token* | String | The FCM token used by Santa to listen for FCM messages. Unique for every machine. No default. |
| fcm_full_sync_interval* | Integer | The full sync interval if a fcm_token is set. Defaults to 14400 secs (4 hours). |
| fcm_global_rule_sync_deadline* | Integer | The max time to wait before performing a rule sync when a global rule sync FCM message is received. This allows syncing to be staggered for global events to avoid spikes in server load. Defaults to 600 secs (10 min). |
| enable_bundles* | Bool | If set to `True` the bundle scanning feature is enabled. Defaults to `False`. |
| enabled_transitive_whitelisting | Bool | If set to `True` the transitive whitelisting feature is enabled. Defaults to `False`. |
| enabled_transitive_rules | Bool | If set to `True` the transitive rule feature is enabled. Defaults to `False`. |
*Held only in memory. Not persistent upon process restart.

View File

@@ -0,0 +1,65 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1">
<dict>
<!-- See https://developer.apple.com/documentation/devicemanagement/systemextensions for payload descriptions -->
<key>PayloadUUID</key>
<string>40C19D5B-76D7-4C1C-BC9D-2F7EB29CFF4D</string>
<key>PayloadType</key>
<string>Configuration</string>
<key>PayloadOrganization</key>
<string></string>
<key>PayloadIdentifier</key>
<string>com.google.santa.system-extension-policy.40C19D5B-76D7-4C1C-BC9D-2F7EB29CFF4D</string>
<key>PayloadDisplayName</key>
<string>System Extensions</string>
<key>PayloadDescription</key>
<string>Configures your Mac to automatically enable Santa's EndpointSecurityExtension</string>
<key>PayloadVersion</key>
<integer>1</integer>
<key>PayloadEnabled</key>
<true/>
<key>PayloadRemovalDisallowed</key>
<true/>
<key>PayloadScope</key>
<string>System</string>
<key>PayloadContent</key>
<array>
<dict>
<key>PayloadUUID</key>
<string>98D01A7B-ADC1-43C8-AB8E-8BDC25FCA3C9</string>
<key>PayloadType</key>
<string>com.apple.system-extension-policy</string>
<key>PayloadOrganization</key>
<string></string>
<key>PayloadIdentifier</key>
<string>com.google.santa.system-extension-policy.98D01A7B-ADC1-43C8-AB8E-8BDC25FCA3C9</string>
<key>PayloadDisplayName</key>
<string>System Extensions</string>
<key>PayloadDescription</key>
<string/>
<key>PayloadVersion</key>
<integer>1</integer>
<key>PayloadEnabled</key>
<true/>
<key>AllowUserOverrides</key>
<true/>
<key>AllowedSystemExtensions</key>
<dict>
<key>EQHXZ8M8AV</key>
<array>
<string>com.google.santa.daemon</string>
</array>
</dict>
<key>AllowedSystemExtensionTypes</key>
<dict>
<key>EQHXZ8M8AV</key>
<array>
<string>EndpointSecurityExtension</string>
</array>
</dict>
</dict>
</array>
</dict>
</plist>

View File

@@ -0,0 +1,90 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<!-- See https://developer.apple.com/documentation/devicemanagement/privacypreferencespolicycontrol for payload descriptions -->
<key>PayloadContent</key>
<array>
<dict>
<key>PayloadDescription</key>
<string>Configures Privacy Preferences Policy Control settings</string>
<key>PayloadDisplayName</key>
<string>Privacy Preferences Policy Control</string>
<key>PayloadIdentifier</key>
<string>com.google.santa.TCC.configuration-profile-policy.2416BA4B-CBFC-4719-B02F-20251B881D6F</string>
<key>PayloadOrganization</key>
<string></string>
<key>PayloadType</key>
<string>com.apple.TCC.configuration-profile-policy</string>
<key>PayloadUUID</key>
<string>2416BA4B-CBFC-4719-B02F-20251B881D6F</string>
<key>PayloadVersion</key>
<integer>1</integer>
<key>Services</key>
<dict>
<key>SystemPolicyAllFiles</key>
<array>
<dict>
<key>Allowed</key>
<true/>
<key>CodeRequirement</key>
<string>identifier "com.google.santa.daemon" and anchor apple generic and certificate 1[field.1.2.840.113635.100.6.2.6] /* exists */ and certificate leaf[field.1.2.840.113635.100.6.1.13] /* exists */ and certificate leaf[subject.OU] = EQHXZ8M8AV</string>
<key>Comment</key>
<string></string>
<key>Identifier</key>
<string>com.google.santa.daemon</string>
<key>IdentifierType</key>
<string>bundleID</string>
<key>StaticCode</key>
<false/>
</dict>
<dict>
<key>Allowed</key>
<true/>
<key>CodeRequirement</key>
<string>identifier "com.google.santa.bundleservice" and anchor apple generic and certificate 1[field.1.2.840.113635.100.6.2.6] /* exists */ and certificate leaf[field.1.2.840.113635.100.6.1.13] /* exists */ and certificate leaf[subject.OU] = EQHXZ8M8AV</string>
<key>Comment</key>
<string></string>
<key>Identifier</key>
<string>com.google.santa.bundleservice</string>
<key>IdentifierType</key>
<string>bundleID</string>
<key>StaticCode</key>
<false/>
</dict>
<dict>
<key>Allowed</key>
<true/>
<key>CodeRequirement</key>
<string>identifier "com.google.santa" and anchor apple generic and certificate 1[field.1.2.840.113635.100.6.2.6] /* exists */ and certificate leaf[field.1.2.840.113635.100.6.1.13] /* exists */ and certificate leaf[subject.OU] = EQHXZ8M8AV</string>
<key>Comment</key>
<string></string>
<key>Identifier</key>
<string>com.google.santa</string>
<key>IdentifierType</key>
<string>bundleID</string>
<key>StaticCode</key>
<false/>
</dict>
</array>
</dict>
</dict>
</array>
<key>PayloadDescription</key>
<string>tcc.configuration-profile-policy.santa.example</string>
<key>PayloadDisplayName</key>
<string>tcc.configuration-profile-policy.santa.example</string>
<key>PayloadIdentifier</key>
<string>com.google.santa.TCC.configuration-profile-policy.089CBCFB-F2AA-407C-9F2A-A12967FE20BC</string>
<key>PayloadOrganization</key>
<string></string>
<key>PayloadScope</key>
<string>System</string>
<key>PayloadType</key>
<string>Configuration</string>
<key>PayloadUUID</key>
<string>089CBCFB-F2AA-407C-9F2A-A12967FE20BC</string>
<key>PayloadVersion</key>
<integer>1</integer>
</dict>
</plist>

View File

@@ -1,16 +1,34 @@
# Events
Events are a defined set of data, core to how Santa interacts with a sync server. Events are generated when there is a blocked `execve()` while in Lockdown or Monitor mode. Events are also generated in Monitor mode for an `execve()` that was allowed to run, but would have been blocked in Lockdown mode. This allows an admin to roll out Santa to their macOS fleet in Monitor mode but still collect meaningful data. The events collected while in Monitor mode can be used to build a reasonably comprehensive whitelist of signing certificates and binaries before switching the fleet to Lockdown mode.
Events are a defined set of data, core to how Santa interacts with a sync
server. Events are generated when there is a blocked `execve()` while in
Lockdown or Monitor mode. Events are also generated in Monitor mode for an
`execve()` that was allowed to run, but would have been blocked in Lockdown
mode. This allows an admin to roll out Santa to their macOS fleet in Monitor
mode but still collect meaningful data. The events collected while in Monitor
mode can be used to build a reasonably comprehensive allowlist of signing
certificates and binaries before switching the fleet to Lockdown mode.
##### Event Data
Events begin their life as an [SNTStoredEvent](https://github.com/google/santa/blob/master/Source/common/SNTStoredEvent.h) object. The SNTStoredEvent class is just a simple storage class that has properties for all the relevant bits of information. More importantly the class implements the [NSSecureCoding](https://developer.apple.com/documentation/foundation/nssecurecoding?language=objc) protocol. This allows the objects to be encoded and decoded for storage in the events sqlite3 database on disk and sent over XPC to another process.
Events begin their life as an
[SNTStoredEvent](https://github.com/google/santa/blob/master/Source/common/SNTStoredEvent.h)
object. The SNTStoredEvent class is just a simple storage class that has
properties for all the relevant bits of information. More importantly the class
implements the
[NSSecureCoding](https://developer.apple.com/documentation/foundation/nssecurecoding?language=objc)
protocol. This allows the objects to be encoded and decoded for storage in the
events sqlite3 database on disk and sent over XPC to another process.
Events are temporarily stored in a database until they are uploaded. The format is subject the change; accessing the events database directly will most likely break in future releases. If direct access to the events database is required, raise a [issue on the Santa GitHub](https://github.com/google/santa/issues).
Events are temporarily stored in a database until they are uploaded. The format
is subject the change; accessing the events database directly will most likely
break in future releases. If direct access to the events database is required,
raise a [issue on the Santa GitHub](https://github.com/google/santa/issues).
###### JSON
Before an event is uploaded to a sync server, the event data is copied into a JSON blob. Here is an example of Firefox being blocked and sent for upload:
Before an event is uploaded to a sync server, the event data is copied into a
JSON blob. Here is an example of Firefox being blocked and sent for upload:
```json
{
@@ -73,18 +91,30 @@ Before an event is uploaded to a sync server, the event data is copied into a JS
}
```
##### Event Lifecycle
1. santad generates a new event
2. santad compares, or adds if not present, the event's SHA-256 file hash to an in-memory cache with a timeout of 10 min. If an event with an matching hash is present in cache, the event is dropped.
3. santad saves the event to `/var/db/santa/events.db` with a unique ID assigned as the key.
4. santad sends an XPC message to the santactl daemon. The message contains the event with instructions to upload the event immediately. This is non-blocking and is performed on a background thread.
1. santad generates a new event
2. santad compares, or adds if not present, the event's SHA-256 file hash to an
in-memory cache with a timeout of 10 min. If an event with an matching hash
is present in cache, the event is dropped.
3. santad saves the event to `/var/db/santa/events.db` with a unique ID
assigned as the key.
4. santad sends an XPC message to the santactl daemon. The message contains the
event with instructions to upload the event immediately. This is
non-blocking and is performed on a background thread.
##### Bundle Events
Bundle events are a special type of event that are generated when a sync server supports receiving the associated bundle events, instead of just the original event. For example: `/Applications/Keynote.app/Contents/MacOS/Keynote` is blocked and an event representing the binary is uploaded. A whitelist rule is created for that one binary. Great, you can now run `/Applications/Keynote.app/Contents/MacOS/Keynote`, but what about all the other supporting binaries contained in the bundle? You would have to wait until they are executed until an event would be generated. It is very common for a bundle to contain multiple binaries, as shown here with Keynote.app. Waiting to get a block is not a very good user experience.
Bundle events are a special type of event that are generated when a sync server
supports receiving the associated bundle events, instead of just the original
event. For example: `/Applications/Keynote.app/Contents/MacOS/Keynote` is
blocked and an event representing the binary is uploaded. An allow rule is
created for that one binary. Great, you can now run
`/Applications/Keynote.app/Contents/MacOS/Keynote`, but what about all the other
supporting binaries contained in the bundle? You would have to wait until they
are executed until an event would be generated. It is very common for a bundle
to contain multiple binaries, as shown here with Keynote.app. Waiting to get a
block is not a very good user experience.
```sh
⇒ santactl bundleinfo /Applications/Keynote.app
@@ -92,50 +122,59 @@ Hashing time: 1047 ms
9 events found
BundleHash: b475667ab1ab6eddea48bfc2bed76fcef89b8f85ed456c8068351292f7cb4806
BundleID: com.apple.iWork.Keynote
SHA-256: be3aa404ee79c2af863132b93b0eedfdbc34c6e35d4fda2ade6dd637692ead84
Path: /Applications/Keynote.app/Contents/XPCServices/com.apple.iWork.MovieCompatibilityConverter.xpc/Contents/MacOS/com.apple.iWork.MovieCompatibilityConverter
SHA-256: be3aa404ee79c2af863132b93b0eedfdbc34c6e35d4fda2ade6dd637692ead84
Path: /Applications/Keynote.app/Contents/XPCServices/com.apple.iWork.MovieCompatibilityConverter.xpc/Contents/MacOS/com.apple.iWork.MovieCompatibilityConverter
BundleID: com.apple.iWork.Keynote
SHA-256: 3b2582fd5e7652b653276b3980c248dc973e8082e9d0678c96a08d7d1a8366ba
Path: /Applications/Keynote.app/Contents/XPCServices/com.apple.iWork.PICTConverter.xpc/Contents/MacOS/com.apple.iWork.PICTConverter
SHA-256: 3b2582fd5e7652b653276b3980c248dc973e8082e9d0678c96a08d7d1a8366ba
Path: /Applications/Keynote.app/Contents/XPCServices/com.apple.iWork.PICTConverter.xpc/Contents/MacOS/com.apple.iWork.PICTConverter
BundleID: com.apple.iWork.Keynote
SHA-256: f1bf3be05d511d7c7f651cf7b130d4977f8d28d0bfcd7c5de4144b95eaab7ad7
Path: /Applications/Keynote.app/Contents/XPCServices/com.apple.iWork.ExternalResourceAccessor.xpc/Contents/XPCServices/com.apple.iWork.TCMovieExtractor.xpc/Contents/MacOS/com.apple.iWork.TCMovieExtractor
SHA-256: f1bf3be05d511d7c7f651cf7b130d4977f8d28d0bfcd7c5de4144b95eaab7ad7
Path: /Applications/Keynote.app/Contents/XPCServices/com.apple.iWork.ExternalResourceAccessor.xpc/Contents/XPCServices/com.apple.iWork.TCMovieExtractor.xpc/Contents/MacOS/com.apple.iWork.TCMovieExtractor
BundleID: com.apple.iWork.Keynote
SHA-256: b59bc8548c91088a40d9023abb5d22fa8731b4aa17693fcb5b98c795607d219a
Path: /Applications/Keynote.app/Contents/XPCServices/com.apple.iWork.BitmapTracer.xpc/Contents/MacOS/com.apple.iWork.BitmapTracer
SHA-256: b59bc8548c91088a40d9023abb5d22fa8731b4aa17693fcb5b98c795607d219a
Path: /Applications/Keynote.app/Contents/XPCServices/com.apple.iWork.BitmapTracer.xpc/Contents/MacOS/com.apple.iWork.BitmapTracer
BundleID: com.apple.iWork.Keynote
SHA-256: 08cb407f541d867f1a63dc3ae44eeedd5181ca06c61df6ef62b5dc7192951a4b
Path: /Applications/Keynote.app/Contents/XPCServices/com.apple.iWork.TCUtilities32.xpc/Contents/MacOS/com.apple.iWork.TCUtilities32
SHA-256: 08cb407f541d867f1a63dc3ae44eeedd5181ca06c61df6ef62b5dc7192951a4b
Path: /Applications/Keynote.app/Contents/XPCServices/com.apple.iWork.TCUtilities32.xpc/Contents/MacOS/com.apple.iWork.TCUtilities32
BundleID: com.apple.iWork.Keynote
SHA-256: b965ae7be992d1ce818262752d0cf44297a88324a593c67278d78ca4d16fcc39
Path: /Applications/Keynote.app/Contents/XPCServices/com.apple.iWork.ExternalResourceAccessor.xpc/Contents/XPCServices/com.apple.iWork.TCMovieExtractor.xpc/Contents/XPCServices/com.apple.iWork.TCMovieExtractor.TCUtilities32.xpc/Contents/MacOS/com.apple.iWork.TCMovieExtractor.TCUtilities32
SHA-256: b965ae7be992d1ce818262752d0cf44297a88324a593c67278d78ca4d16fcc39
Path: /Applications/Keynote.app/Contents/XPCServices/com.apple.iWork.ExternalResourceAccessor.xpc/Contents/XPCServices/com.apple.iWork.TCMovieExtractor.xpc/Contents/XPCServices/com.apple.iWork.TCMovieExtractor.TCUtilities32.xpc/Contents/MacOS/com.apple.iWork.TCMovieExtractor.TCUtilities32
BundleID: com.apple.iWork.Keynote
SHA-256: 59668dc27314f0f6f5daa5f02b564c176f64836c88e2dfe166e90548f47336f1
Path: /Applications/Keynote.app/Contents/MacOS/Keynote
SHA-256: 59668dc27314f0f6f5daa5f02b564c176f64836c88e2dfe166e90548f47336f1
Path: /Applications/Keynote.app/Contents/MacOS/Keynote
BundleID: com.apple.iWork.Keynote
SHA-256: 7ce324f919b14e14d327004b09f83ca81345fd4438c87ead4b699f89e9485595
Path: /Applications/Keynote.app/Contents/XPCServices/com.apple.iWork.ExternalResourceAccessor.xpc/Contents/XPCServices/com.apple.iWork.ExternalResourceValidator.xpc/Contents/MacOS/com.apple.iWork.ExternalResourceValidator
SHA-256: 7ce324f919b14e14d327004b09f83ca81345fd4438c87ead4b699f89e9485595
Path: /Applications/Keynote.app/Contents/XPCServices/com.apple.iWork.ExternalResourceAccessor.xpc/Contents/XPCServices/com.apple.iWork.ExternalResourceValidator.xpc/Contents/MacOS/com.apple.iWork.ExternalResourceValidator
BundleID: com.apple.iWork.Keynote
SHA-256: 6b47f551565d886388eeec5e876b6de9cdd71ef36d43b0762e6ebf02bdd8515d
Path: /Applications/Keynote.app/Contents/XPCServices/com.apple.iWork.ExternalResourceAccessor.xpc/Contents/MacOS/com.apple.iWork.ExternalResourceAccessor
SHA-256: 6b47f551565d886388eeec5e876b6de9cdd71ef36d43b0762e6ebf02bdd8515d
Path: /Applications/Keynote.app/Contents/XPCServices/com.apple.iWork.ExternalResourceAccessor.xpc/Contents/MacOS/com.apple.iWork.ExternalResourceAccessor
```
Bundle events provide a mechanism to generate and upload events for all the executable Mach-O binaries within a bundle. To enable bundle event generation a configuration must be set in the preflight sync stage on the sync server. Once set the sync server can use bundle events to drive a better user experience.
Bundle events provide a mechanism to generate and upload events for all the
executable Mach-O binaries within a bundle. To enable bundle event generation a
configuration must be set in the preflight sync stage on the sync server. Once
set the sync server can use bundle events to drive a better user experience.
Bundle events can be differentiated by the existence of these fields:
| Field | Value |
| ------------------------ | ---------------------------------------- |
| decision | BUNDLE_BINARY |
| file_bundle_hash | Super Hash of all binary hashes |
| file_bundle_hash_millis | The time in milliseconds it took to find all of the binaries, hash and produce a super hash |
| file_bundle_binary_count | Number of binaries within the bundle |
| Field | Value |
| ------------------------ | ----------------------------------------------- |
| decision | BUNDLE_BINARY |
| file_bundle_hash | Super Hash of all binary hashes |
| file_bundle_hash_millis | The time in milliseconds it took to find all of |
| | the binaries, hash and produce a super hash |
| file_bundle_binary_count | Number of binaries within the bundle |
To avoid redundant uploads of a bundle event Santa will wait for the sync server to ask for them. The server will respond to event uploads with a request like this:
To avoid redundant uploads of a bundle event Santa will wait for the sync server
to ask for them. The server will respond to event uploads with a request like
this:
| Field | Value |
| ---------------------------- | ---------------------------------------- |
| event_upload_bundle_binaries | An array of bundle hashes that the sync server needs to be uploaded |
When santactl receives this type of request, it sends an XPC reply to santad to save all the bundle events to the events.db. It then attempts to upload all the bundle events, purging the successes from the events.db. Any failures will be uploaded during the next full sync.
| Field | Value |
| ---------------------------- | --------------------------------------- |
| event_upload_bundle_binaries | An array of bundle hashes that the sync |
| | server needs to be uploaded |
When santactl receives this type of request, it sends an XPC reply to santad to
save all the bundle events to the events.db. It then attempts to upload all the
bundle events, purging the successes from the events.db. Any failures will be
uploaded during the next full sync.

View File

@@ -1,43 +1,62 @@
# Interprocess Communication (IPC)
Most IPC within Santa is done by way of Apple's [XPC](https://developer.apple.com/documentation/xpc?language=objc). Santa wraps [NSXPCConnection](https://developer.apple.com/documentation/foundation/nsxpcconnection?language=objc) to provide client multiplexing, signature validation of connecting clients and forced connection establishment. This is called SNTXPCConnection.
Most IPC within Santa is done by way of Apple's
[XPC](https://developer.apple.com/documentation/xpc?language=objc). Santa wraps
[NSXPCConnection](https://developer.apple.com/documentation/foundation/nsxpcconnection?language=objc)
to provide client multiplexing, signature validation of connecting clients and
forced connection establishment. This is called SNTXPCConnection.
Communication between santad and santa-driver (KEXT) is done with a [IOUserClient](https://developer.apple.com/documentation/kernel/iouserclient?language=objc) subclass and IOKit/IOKitLib.h functions.
Communication between santad and santa-driver (KEXT) is done with a
[IOUserClient](https://developer.apple.com/documentation/kernel/iouserclient?language=objc)
subclass and IOKit/IOKitLib.h functions.
##### Who starts who?
The santad and Santa (GUI) processes are both started and kept alive by launchd as a LaunchDaemon and a LaunchAgent, respectively. This means santad runs as root and Santa (GUI) runs as the console user.
The santad and Santa (GUI) processes are both started and kept alive by launchd
as a LaunchDaemon and a LaunchAgent, respectively. This means santad runs as
root and Santa (GUI) runs as the console user.
There can be multiple Santa (GUI) processes running, one per user logged into the GUI (assuming fast-user switching is enabled). While multiple processes might be running, only the one for the user currently logged-in will be connected to santad and receiving notifications.
There can be multiple Santa (GUI) processes running, one per user logged into
the GUI (assuming fast-user switching is enabled). While multiple processes
might be running, only the one for the user currently logged-in will be
connected to santad and receiving notifications.
When using a sync server, the santactl process is started by santad. Before the new process starts, all privileges are dropped. santactl runs as _nobody_.
The santabs process is started by launchd via an XPC service connection from santad. XPC services inherit their initiator's privileges meaning santabs runs as root, which is necessary to ensure it has permission to read all files.
| Process | Parent Process | Running User |
| -------- | -------------- | ------------ |
| santad | launchd | root |
| Santa | launchd | user |
| santactl | santad | nobody |
| santabs | launchd | root |
When using a sync server, the santactl process is started by santad. Before the
new process starts, all privileges are dropped. santactl runs as _nobody_.
The santabs process is started by launchd via an XPC service connection from
santad. XPC services inherit their initiator's privileges meaning santabs runs
as root, which is necessary to ensure it has permission to read all files.
Process | Parent Process | Running User
-------- | -------------- | ------------
santad | launchd | root
Santa | launchd | user
santactl | santad | nobody
santabs | launchd | root
##### Who communicates with who?
In short, santad has two-way communication with every other process. In addition, Santa and santabs have two-way communication between each other. For other combinations, there is no direct communication.
In short, santad has two-way communication with every other process. In
addition, Santa and santabs have two-way communication between each other. For
other combinations, there is no direct communication.
![Santa IPC](santa_ipc.png)
##### SNTXPCConnection and two way communication
`SNTXPCConnection` enforces a server / client model for XPC connections. This allows for strong signature validation and forced connection establishment. The only problem with this model is the lack of two-way communication. For example, process A can call methods on process B and retrieve a response, but process B cannot call methods on process A.
`SNTXPCConnection` enforces a server / client model for XPC connections. This
allows for strong signature validation and forced connection establishment. The
only problem with this model is the lack of two-way communication. For example,
process A can call methods on process B and retrieve a response, but process B
cannot call methods on process A.
To accomplish two-way communication, the following approach can be used:
1. Process A creates a server with an anonymous `NSXPCListener`.
2. Process A sends the anonymous `NSXPCListenerEndpoint` to process B over an already established `SNTXPCConnection`.
3. Process B can now communicate directly with process A.
This is a powerful notion. It enables forced connection establishment between both processes, which is critical when reliability is a concern.
1. Process A creates a server with an anonymous `NSXPCListener`.
2. Process A sends the anonymous `NSXPCListenerEndpoint` to process B over an
already established `SNTXPCConnection`.
3. Process B can now communicate directly with process A.
This is a powerful notion. It enables forced connection establishment between
both processes, which is critical when reliability is a concern.

View File

@@ -1,6 +1,9 @@
# Logs
Santa currently logs to `/var/db/santa/santa.log` by default. All executions and disk mounts are logged here. File operations can also be configured to be logged. See the `FileChangesRegex` key in the [configuration.md](../deployment/configuration.md) document.
Santa currently logs to `/var/db/santa/santa.log` by default. All executions and
disk mounts are logged here. File operations can also be configured to be
logged. See the `FileChangesRegex` key in the
[configuration.md](../deployment/configuration.md) document.
To view the logs:
@@ -8,23 +11,30 @@ To view the logs:
tail -F /var/db/santa/santa.log
```
The `-F` will continue watching the path even when the current file fills up and rolls over.
The `-F` will continue watching the path even when the current file fills up and
rolls over.
##### macOS Unified Logging System (ULS)
Currently all of the most recent releases of Santa are built with the macOS 10.11 SDK. This allows Santa to continue to log to Apple System Logger (ASL) instead of ULS. However, on macOS 10.12+ all of the Kernel logs are sent to ULS. See the KEXT Logging section below for more details.
Currently all of the most recent releases of Santa are built with the macOS
10.11 SDK. This allows Santa to continue to log to Apple System Logger (ASL)
instead of ULS. However, on macOS 10.12+ all of the Kernel logs are sent to ULS.
See the KEXT Logging section below for more details.
If you are building Santa yourself and using the macOS 10.12+ SDKs, Santa's logs will be sent to ULS.
If you are building Santa yourself and using the macOS 10.12+ SDKs, Santa's logs
will be sent to ULS.
Work is currently underway to bypass ASL and ULS altogether, allowing Santa to continue logging to `/var/db/santa/santa.log`. This change will also allow us to add alternative logging formats, like Protocol Buffer or JSON.
Work is currently underway to bypass ASL and ULS altogether, allowing Santa to
continue logging to `/var/db/santa/santa.log`. This change will also allow us to
add alternative logging formats, like Protocol Buffer or JSON.
##### KEXT Logging
Streaming logs from the santa-driver KEXT does not work properly. Logs are generated but they will likely be garbled or show inaccurate data.
Streaming logs from the santa-driver KEXT does not work properly. Logs are
generated but they will likely be garbled or show inaccurate data.
Instead, `show` can be used to view the santa-driver KEXT logs:
```sh
/usr/bin/log show --info --debug --predicate 'senderImagePath == "/Library/Extensions/santa-driver.kext/Contents/MacOS/santa-driver"'
```

View File

@@ -1,6 +1,7 @@
# Mode
Santa can run in one of two modes, Lockdown or Monitor. To check the current status run the following command:
Santa can run in one of two modes, Lockdown or Monitor. To check the current
status run the following command:
```sh
⇒ santactl status
@@ -27,27 +28,39 @@ Santa can run in one of two modes, Lockdown or Monitor. To check the current sta
##### Monitor mode
The default mode. Running Santa in Monitor Mode will stop any binaries matching blacklist rules, but will not stop unknown binaries from running. This is a flexible state, allowing virtually zero user interruption but still gives protection against known blacklisted binaries. In addition execution events that would have been blocked in Lockdown mode are generated and can be collected and analyzed by a sync server.
The default mode. Running Santa in Monitor Mode will stop any binaries matching
block rules, but will not stop unknown binaries from running. This is a flexible
state, allowing virtually zero user interruption but still gives protection
against known blocked binaries. In addition execution events that would have
been blocked in Lockdown mode are generated and can be collected and analyzed by
a sync server.
##### Lockdown mode
Running Santa in Lockdown Mode will stop all blacklisted binaries and additionally will prevent all unknown binaries from running. This means that if the binary has no rules or scopes that apply, then it will be blocked.
Running Santa in Lockdown Mode will stop all blocked binaries and additionally
will prevent all unknown binaries from running. This means that if the binary
has no rules or scopes that apply, then it will be blocked.
##### Changing Modes
There are two ways to change the running mode: changing the configuration profile and with a sync server configuration.
There are two ways to change the running mode: changing the configuration
profile and with a sync server configuration.
###### Change modes with the configuration profile
Set the `ClientMode` in your configuration profile to the integer value `1` for MONITOR or `2` for LOCKDOWN.
Set the `ClientMode` in your configuration profile to the integer value `1` for
MONITOR or `2` for LOCKDOWN.
```xml
<key>ClientMode</key>
<integer>1</integer>
```
Install your new configuration profile, it will overwrite any old `com.google.santa` profiles you may have already install. See the [configuration](../deployment/configuration.md) document for more details.
Install your new configuration profile, it will overwrite any old
`com.google.santa` profiles you may have already install. See the
[configuration](../deployment/configuration.md) document for more details.
###### Change modes with a sync server
The mode is set in the preflight sync stage. Use the key `client_mode` and a value of `MONITOR` or `LOCKDOWN`.
The mode is set in the preflight sync stage. Use the key `client_mode` and a
value of `MONITOR` or `LOCKDOWN`.

View File

@@ -1,14 +1,24 @@
# Rules
Rules provide the primary evaluation mechanism for whitelisting and blacklisting binaries with Santa on macOS. There are two types of rules: binary and certificate.
Rules provide the primary evaluation mechanism for allowing and blocking
binaries with Santa on macOS. There are two types of rules: binary and
certificate.
##### Binary Rules
Binary rules use the SHA-256 hash of the entire binary as an identifier. This is the most specific rule in Santa. Even a small change in the binary will alter the SHA-256 hash, invalidating the rule.
Binary rules use the SHA-256 hash of the entire binary as an identifier. This is
the most specific rule in Santa. Even a small change in the binary will alter
the SHA-256 hash, invalidating the rule.
##### Certificate Rules
Certificate rules are formed from the SHA-256 fingerprint of an X.509 leaf signing certificate. This is a powerful rule type that has a much broader reach than an individual binary rule. A signing certificate can sign any number of binaries. Whitelisting or blacklisting just a few key signing certificates can cover the bulk of an average user's binaries. The leaf signing certificate is the only part of the chain that is evaluated. Though the whole chain is available for viewing.
Certificate rules are formed from the SHA-256 fingerprint of an X.509 leaf
signing certificate. This is a powerful rule type that has a much broader reach
than an individual binary rule. A signing certificate can sign any number of
binaries. Allowing or blocking just a few key signing certificates can cover the
bulk of an average user's binaries. The leaf signing certificate is the only
part of the chain that is evaluated. Though the whole chain is available for
viewing.
```sh
⇒ santactl fileinfo /Applications/Dropbox.app --key "Signing Chain"
@@ -38,67 +48,84 @@ Signing Chain:
Valid Until : 2035/02/09 16:40:36 -0500
```
If you wanted to whitelist or blacklist all software signed with this perticular Dropbox signing certificate you would use the leaf SHA-256 fingerprint.
If you wanted to allow or block all software signed with this particular Dropbox
signing certificate you would use the leaf SHA-256 fingerprint.
`2a0417257348a20f96c9de0486b44fcc7eaeaeb7625b207591b8109698c02dd2`
Santa does not evaluate the `Valid From` or `Valid Until` fields, nor does it check the Certificate Revocation List (CRL) or the Online Certificate Status Protocol (OCSP) for revoked certificates. Adding rules for the certificate chain's intermediates or roots has no effect on binaries signing by a leaf. Santa ignores the chain and is only concerned with the leaf certificate's SHA-256 hash.
Santa does not evaluate the `Valid From` or `Valid Until` fields, nor does it
check the Certificate Revocation List (CRL) or the Online Certificate Status
Protocol (OCSP) for revoked certificates. Adding rules for the certificate
chain's intermediates or roots has no effect on binaries signing by a leaf.
Santa ignores the chain and is only concerned with the leaf certificate's
SHA-256 hash.
##### Rule Evaluation
When a process is trying to `execve()` santad retrieves information on the binary, including a hash of the entire file and the signing chain (if any). The hash and signing leaf certificate are then passed through the [SNTPolicyProcessor](https://github.com/google/santa/blob/master/Source/santad/SNTPolicyProcessor.h). Rules are evaluated from most specific to least specific. First binary (either whitelist or blacklist), then certificate (either whitelist or blacklist). If no rules are found that apply, scopes are then searched. See the [scopes.md](scopes.md) document for more information on scopes.
When a process is trying to `execve()` `santad` retrieves information on the
binary, including a hash of the entire file and the signing chain (if any). The
hash and signing leaf certificate are then passed through the
[SNTPolicyProcessor](https://github.com/google/santa/blob/master/Source/santad/SNTPolicyProcessor.h).
Rules are evaluated from most specific to least specific. First binary (either
allow or block), then certificate (either allow or block). If no rules are found
that apply, scopes are then searched. See the [scopes.md](scopes.md) document
for more information on scopes.
You can use the `santactl fileinfo` command to check the status of any given binary on the filesystem.
You can use the `santactl fileinfo` command to check the status of any given
binary on the filesystem.
###### Whitelisted with a Binary Rule
###### Allowed with a Binary Rule
```sh
⇒ santactl fileinfo /Applications/Hex\ Fiend.app --key Rule
Whitelisted (Binary)
Allowed (Binary)
```
###### Whitelisted with a Certificate Rule
###### Allowed with a Certificate Rule
```sh
⇒ santactl fileinfo /Applications/Safari.app --key Rule
Whitelisted (Certificate)
Allowed (Certificate)
```
###### Blacklisted with a Binary Rule
###### Blocked with a Binary Rule
```sh
⇒ santactl fileinfo /usr/bin/yes --key Rule
Blacklisted (Binary)
Blocked (Binary)
```
###### Blacklisted with a Certificate Rule
###### Blocked with a Certificate Rule
```sh
⇒ santactl fileinfo /Applications/Malware.app --key Rule
Blacklisted (Certificate)
Blocked (Certificate)
```
You can also check arbitrary SHA-256 binary and certificate hashes for rules. The rule verb needs to be run with root privileges.
You can also check arbitrary SHA-256 binary and certificate hashes for rules.
The rule verb needs to be run with root privileges.
For checking the SHA-256 hash of `/usr/bin/yes`:
```sh
sudo santactl rule --check --sha256 $(santactl fileinfo --key SHA-256 /usr/bin/yes)
Blacklisted (Binary)
Blocked (Binary)
```
For checking the SHA-256 hash of `/usr/bin/yes ` signing certificate:
For checking the SHA-256 hash of `/usr/bin/yes` signing certificate:
```sh
⇒ sudo santactl rule --check --certificate --sha256 $(santactl fileinfo --cert-index 1 --key SHA-256 /usr/bin/yes)
Whitelisted (Certificate)
Allowed (Certificate)
```
##### Built-in rules
To avoid blocking any Apple system binaries or Santa binaries, santad will create 2 immutable certificate rules at startup:
To avoid blocking any Apple system binaries or Santa binaries, `santad` will
create 2 immutable certificate rules at startup:
* The signing certificate santad is signed with
* The signing certificate launchd is signed with
* The signing certificate santad is signed with
* The signing certificate launchd is signed with
By creating these two rules at startup, Santa should never block critical Apple system binaries or other Santa components.
By creating these two rules at startup, Santa should never block critical Apple
system binaries or other Santa components.

View File

@@ -1,16 +1,26 @@
# santa-driver
santa-driver is a macOS [kernel extension](https://developer.apple.com/library/content/documentation/Darwin/Conceptual/KEXTConcept/KEXTConceptIntro/introduction.html) (KEXT) that makes use of the [Kernel Authorization](https://developer.apple.com/library/content/technotes/tn2127/_index.html) (Kauth) KPI. This allows santa-driver to listen for events and either deny or defer the decision of those events. The santa-driver acts as an intermediary layer between Kauth and santad, with some caching to lower the overhead of decision making.
santa-driver is a macOS
[kernel extension](https://developer.apple.com/library/content/documentation/Darwin/Conceptual/KEXTConcept/KEXTConceptIntro/introduction.html)
(KEXT) that makes use of the
[Kernel Authorization](https://developer.apple.com/library/content/technotes/tn2127/_index.html)
(Kauth) KPI. This allows santa-driver to listen for events and either deny or
defer the decision of those events. The santa-driver acts as an intermediary
layer between Kauth and santad, with some caching to lower the overhead of
decision making.
##### Kauth
santa-driver utilizes two Kauth scopes `KAUTH_SCOPE_VNODE` and `KAUTH_SCOPE_FILEOP `. It registers itself with the Kauth API by calling `kauth_listen_scope()` for each scope. This function takes three arguments:
santa-driver utilizes two Kauth scopes `KAUTH_SCOPE_VNODE` and
`KAUTH_SCOPE_FILEOP`. It registers itself with the Kauth API by calling
`kauth_listen_scope()` for each scope. This function takes three arguments:
* `const char *scope`
* `kauth_scope_callback_t _callback`_
* `void *contex`
* `const char *scope`
* `kauth_scope_callback_t _callback`
* `void *context`
It returns a `kauth_listener_t` that is stored for later use, in Santa's case to stop listening.
It returns a `kauth_listener_t` that is stored for later use, in Santa's case to
stop listening.
###### KAUTH_SCOPE_VNODE
@@ -21,7 +31,12 @@ vnode_listener_ = kauth_listen_scope(
KAUTH_SCOPE_VNODE, vnode_scope_callback, reinterpret_cast<void *>(this));
```
The function `vnode_scope_callback` is called for every vnode event. There are many types of vnode events, they complete list can be viewed in the kauth.h. There are many types of vnode events, the complete list can be viewed in kauth.h. Santa is only concerned with regular files generating `KAUTH_VNODE_EXECUTE` [1] and `KAUTH_VNODE_WRITE_DATA` events. All non-regular files and unnecessary vnode events are filtered out.
The function `vnode_scope_callback` is called for every vnode event. There are
many types of vnode events, they complete list can be viewed in the kauth.h.
There are many types of vnode events, the complete list can be viewed in
kauth.h. Santa is only concerned with regular files generating
`KAUTH_VNODE_EXECUTE` [1] and `KAUTH_VNODE_WRITE_DATA` events. All non-regular
files and unnecessary vnode events are filtered out.
Here is how santa-driver stops listening for `KAUTH_SCOPE_VNODE` events:
@@ -29,30 +44,42 @@ Here is how santa-driver stops listening for `KAUTH_SCOPE_VNODE` events:
kauth_unlisten_scope(vnode_listener_);
```
[1] `KAUTH_VNODE_EXECUTE` events that do not have the `KAUTH_VNODE_ACCESS` advisory bit set.
[1] `KAUTH_VNODE_EXECUTE` events that do not have the `KAUTH_VNODE_ACCESS`
advisory bit set.
###### KAUTH_SCOPE_FILEOP
Santa also listens for file operations, this is mainly used for logging [1] and cache invalidation.
Santa also listens for file operations, this is mainly used for logging [1] and
cache invalidation.
* `KAUTH_FILEOP_DELETE`, `KAUTH_FILEOP_RENAME`, `KAUTH_FILEOP_EXCHANGE` and `KAUTH_FILEOP_LINK` are logged
* `KAUTH_FILEOP_EXEC` is used to log `execve()`s. Since the `KAUTH_VNODE_EXECUTE` is used to allow or deny an `execve()` the process arguments have not been setup yet. Since `KAUTH_FILEOP_EXEC` is triggered after an `execve()` it is used to log the `execve()`.
* `KAUTH_FILEOP_DELETE`, `KAUTH_FILEOP_RENAME`, `KAUTH_FILEOP_EXCHANGE` and
`KAUTH_FILEOP_LINK` are logged
* `KAUTH_FILEOP_EXEC` is used to log `execve()`s. Since the
`KAUTH_VNODE_EXECUTE` is used to allow or deny an `execve()` the process
arguments have not been setup yet. Since `KAUTH_FILEOP_EXEC` is triggered
after an `execve()` it is used to log the `execve()`.
[1] `KAUTH_FILEOP_CLOSE` is used to invalidate that file's representation in the cache. If a file has changed it needs to be re-evalauted. This is particularly necessary for files that were added to the cache with an action of allow.
[1] `KAUTH_FILEOP_CLOSE` is used to invalidate that file's representation in the
cache. If a file has changed it needs to be re-evalauted. This is particularly
necessary for files that were added to the cache with an action of allow.
##### Driver Interface
santa-driver implements an [IOUserClient](https://developer.apple.com/documentation/kernel/iouserclient?language=objc) subclass and santad interacts with it through IOKit/IOKitLib.h functions.
santa-driver implements an
[IOUserClient](https://developer.apple.com/documentation/kernel/iouserclient?language=objc)
subclass and santad interacts with it through IOKit/IOKitLib.h functions.
[//]: # "TODO(bur, rah) Flesh out the details"
##### Cache
To aid in performance, santa-driver utilizes a caching system to hold the state of all observed `execve()` events.
To aid in performance, santa-driver utilizes a caching system to hold the state
of all observed `execve()` events.
###### Key
The key is a `uint64_t`. The top 32 bits hold the filesystem ID, while the bottom 32 bits hold the file unique ID. Together we call this the vnode_id.
The key is a `uint64_t`. The top 32 bits hold the filesystem ID, while the
bottom 32 bits hold the file unique ID. Together we call this the vnode_id.
```c++
uint64_t vnode_id = (((uint64_t)fsid << 32) | fileid);
@@ -60,7 +87,9 @@ uint64_t vnode_id = (((uint64_t)fsid << 32) | fileid);
###### Value
The value is a `uint64_t` containing the action necessary, along with the decision timestamp. The action is stored in the top 8 bits. The decision timestamp is stored in the remaining 56 bits.
The value is a `uint64_t` containing the action necessary, along with the
decision timestamp. The action is stored in the top 8 bits. The decision
timestamp is stored in the remaining 56 bits.
```c++
santa_action_t action = (santa_action_t)(cache_val >> 56);
@@ -69,21 +98,34 @@ uint64_t decision_time = (cache_val & ~(0xFF00000000000000));
The possible actions are:
| Actions | Expiry Time | Description |
| ----------------------- | ---------------- | ---------------------------------------- |
| `ACTION_REQUEST_BINARY` | None | Awaiting an allow or deny decision from santad. |
| `ACTION_RESPOND_ALLOW` | None | Allow the `execve()` |
| `ACTION_RESPOND_DENY` | 500 milliseconds | Deny the `execve()`, but re-evalaute after 500 milliseconds. If someone is trying to run a banned binary continually every millisecond for example, only 2 evaluation requests to santad for would occur per second. This mitigates a denial of service type attack on santad. |
| Actions | Expiry Time | Description |
| ----------------------- | ---------------- | ------------------------------ |
| `ACTION_REQUEST_BINARY` | None | Awaiting an allow or deny |
| | | decision from santad. |
| `ACTION_RESPOND_ALLOW` | None | Allow the `execve()` |
| `ACTION_RESPOND_DENY` | 500 milliseconds | Deny the `execve()`, but |
| | | re-evalaute after 500 |
| | | milliseconds. If someone is |
| | | trying to run a banned binary |
| | | continually every millisecond |
| | | for example, only 2 evaluation |
| | | requests to santad for would |
| | | occur per second. This |
| | | mitigates a denial of service |
| | | type attack on santad. |
###### Invalidation
Besides the expiry time for individual entries, the entire cache will be cleared if any of the following events takes place:
Besides the expiry time for individual entries, the entire cache will be cleared
if any of the following events takes place:
* Addition of a blacklist rule
* Addition of a blacklist regex scope
* Cache fills up. This defaults to `5000` entries for the root volume and `500` for all other mounted volumes.
* Addition of a block rule
* Change to the blocked path regex
* Cache fills up. This defaults to `5000` entries for the root volume and
`500` for all other mounted volumes.
To view the current kernel cache count see the "Kernel info" section of `santactl status`:
To view the current kernel cache count see the "Kernel info" section of
`santactl status`:
```sh
⇒ santactl status
@@ -91,4 +133,3 @@ To view the current kernel cache count see the "Kernel info" section of `santact
Root cache count | 107
Non-root cache count | 0
```

View File

@@ -1,11 +1,13 @@
# Santa GUI
The Santa GUI process is pretty simple. It's only job is the display user GUI notifications. There are two types of notifications it can display:
The Santa GUI process is pretty simple. It's only job is the display user GUI
notifications. There are two types of notifications it can display:
A notification when an `execve()` is blocked.
![Block](block.png)
Notifications when specific rules arrive (when using FCM for push notifications).
Notifications when specific rules arrive (when using FCM for push
notifications).
![Notification](push.png)

View File

@@ -1,44 +1,55 @@
# santabs
The santabs process is an XPC service for the santa-driver.kext bundle, meaning only binaries within that bundle can launch santabs. It will be launched with the same privileges as its calling process. Currently, santad is the only caller of santabs, so santabs runs as root.
The santabs process is an XPC service for the santa-driver.kext bundle, meaning
only binaries within that bundle can launch santabs. It will be launched with
the same privileges as its calling process. Currently, santad is the only caller
of santabs, so santabs runs as root.
##### Events
The santabs process is quite simple and only does one thing: it generates non-execution events for the contents of a bundle.
The santabs process is quite simple and only does one thing: it generates
non-execution events for the contents of a bundle.
When there is an `execve()` that is blocked within a bundle, a few actions take place:
When there is an `execve()` that is blocked within a bundle, a few actions take
place:
1. The highest ancestor bundle in the tree is found
1. The highest ancestor bundle in the tree is found
* So `/Applications/DVD Player.app/Contents/MacOS/DVD Player` would be `/Applications/DVD Player.app`
* Or `/Applications/Safari.app/Contents/PlugIns/CacheDeleteExtension.appex/Contents/MacOS/CacheDeleteExtension` would be `/Applications/Safari.app`
* So `/Applications/DVD Player.app/Contents/MacOS/DVD Player` would be
`/Applications/DVD Player.app`
* Or
`/Applications/Safari.app/Contents/PlugIns/CacheDeleteExtension.appex/Contents/MacOS/CacheDeleteExtension`
would be `/Applications/Safari.app`
2. The ancestor bundle is then searched for Mach-O executables
2. The ancestor bundle is then searched for Mach-O executables
* For Safari that would currently be 4 binaries
* For Safari that would currently be 4 binaries
* ```sh
Hashing time: 53 ms
4 events found
BundleHash: 718773556ca5ea798f984fde2fe1a5994f175900b26d2964c9358a0f469a4ac6
BundleID: com.apple.Safari
SHA-256: ea872e83a518ce442ed050c4408a448d915e2bae90ef8455ce7805448d864a3e
Path: /Applications/Safari.app/Contents/PlugIns/CacheDeleteExtension.appex/Contents/MacOS/CacheDeleteExtension
BundleID: com.apple.Safari
SHA-256: 1a43283857b1822164f82af274c476204748c0a2894dbcaa11ed17f78e0273cc
Path: /Applications/Safari.app/Contents/MacOS/Safari
BundleID: com.apple.Safari
SHA-256: ab0ac54dd90144931b681d1e84e198c6510be44ac5339437bc004e60777af7ba
Path: /Applications/Safari.app/Contents/Resources/appdiagnose
BundleID: com.apple.Safari
SHA-256: f49c5aa3a7373127d0b4945782b1fa375dd3707d66808fd66b7c0756430defa8
Path: /Applications/Safari.app/Contents/XPCServices/com.apple.Safari.BrowserDataImportingService.xpc/Contents/MacOS/com.apple.Safari.BrowserDataImportingService
```
* ```sh
Hashing time: 53 ms
4 events found
BundleHash: 718773556ca5ea798f984fde2fe1a5994f175900b26d2964c9358a0f469a4ac6
BundleID: com.apple.Safari
SHA-256: ea872e83a518ce442ed050c4408a448d915e2bae90ef8455ce7805448d864a3e
Path: /Applications/Safari.app/Contents/PlugIns/CacheDeleteExtension.appex/Contents/MacOS/CacheDeleteExtension
BundleID: com.apple.Safari
SHA-256: 1a43283857b1822164f82af274c476204748c0a2894dbcaa11ed17f78e0273cc
Path: /Applications/Safari.app/Contents/MacOS/Safari
BundleID: com.apple.Safari
SHA-256: ab0ac54dd90144931b681d1e84e198c6510be44ac5339437bc004e60777af7ba
Path: /Applications/Safari.app/Contents/Resources/appdiagnose
BundleID: com.apple.Safari
SHA-256: f49c5aa3a7373127d0b4945782b1fa375dd3707d66808fd66b7c0756430defa8
Path: /Applications/Safari.app/Contents/XPCServices/com.apple.Safari.BrowserDataImportingService.xpc/Contents/MacOS/com.apple.Safari.BrowserDataImportingService
```
3. Events are created for each binary and the bundle hash is calculated
3. Events are created for each binary and the bundle hash is calculated
4. These events are sent to the sync server for processing
4. These events are sent to the sync server for processing
##### Bundle Hash
The found events are sorted by their file SHA-256 hash. The hashes are concatenated and then SHA-256 hashed. This is now a strong indicator on what Mach-O executables were within the bundle at the time of scan. This can then be verified by the sync server when deciding to generate rules.
The found events are sorted by their file SHA-256 hash. The hashes are
concatenated and then SHA-256 hashed. This is now a strong indicator on what
Mach-O executables were within the bundle at the time of scan. This can then be
verified by the sync server when deciding to generate rules.

View File

@@ -2,10 +2,14 @@
This may be the most complex part of Santa. It does two types of work:
1. It contains all of the code and functionality for syncing with a sync-server.
2. It can be used to view the state and configuration of Santa as a whole. It can also inspect individual files. When running without a sync server it also a supported method of managing the rules database.
1. It contains all of the code and functionality for syncing with a
sync-server.
2. It can be used to view the state and configuration of Santa as a whole. It
can also inspect individual files. When running without a sync server it
also a supported method of managing the rules database.
The details of santactl's syncing functionality are covered in the syncing.md document. This document will cover the status work that santactl performs.
The details of santactl's syncing functionality are covered in the syncing.md
document. This document will cover the status work that santactl performs.
##### status
@@ -33,7 +37,8 @@ To view the status of Santa run `santactl status`
Bundle Scanning | Yes
```
The status command also has the ability to print JSON output `santactl status --json`
The status command also has the ability to print JSON output `santactl status
--json`
```sh
⇒ santactl status --json
@@ -91,9 +96,11 @@ Again, a JSON version is available `santactl version --json`
##### fileinfo
The fileinfo verb is very powerful and can be used to tease out just about anything you wish to know about a file, with respect to the domain of Santa.
The fileinfo verb is very powerful and can be used to tease out just about
anything you wish to know about a file, with respect to the domain of Santa.
Here is an example of using `santactl fileinfo ` to inspect the main executable within `/Applications/Hex Fiend.app`.
Here is an example of using `santactl fileinfo` to inspect the main executable
within `/Applications/Hex Fiend.app`.
```sh
⇒ santactl fileinfo /Applications/Hex\ Fiend.app
@@ -109,7 +116,7 @@ Download Timestamp : 2017/06/29 12:52:16 -0400
Download Agent : com.google.Chrome
Type : Executable (x86-64)
Code-signed : Yes
Rule : Whitelisted (Unknown)
Rule : Allowed (Unknown)
Signing Chain:
1. SHA-256 : ba1be5d2d60a43658a0c6ebf61b577e428439b53ef2e0b96ba90285e2c82a1b2
SHA-1 : 8fdbf6d6c22a97c472fb4961b7733ab0d8830ff7
@@ -148,7 +155,7 @@ Multiple `--key` flags are allowed
```sh
⇒ santactl fileinfo /Applications/Hex\ Fiend.app --key SHA-256 --key Rule
efaf88db065beae61615f6f176c11c751555d2bad3c5da6cdad71635896014f1
Whitelisted (Unknown)
Allowed (Unknown)
```
The `--json` flag can also be used at any point
@@ -157,7 +164,7 @@ The `--json` flag can also be used at any point
⇒ santactl fileinfo /Applications/Hex\ Fiend.app --key SHA-256 --key Rule --json
{
"SHA-256" : "efaf88db065beae61615f6f176c11c751555d2bad3c5da6cdad71635896014f1",
"Rule" : "Whitelisted (Unknown)"
"Rule" : "Allowed (Unknown)"
}
```
@@ -168,147 +175,147 @@ Multiple files are also supported as input
[
{
"SHA-256" : "5d8e161c21fc1a43374c4cf21be05360dbe2ecea0165fd4725ae7a958f2a0b02",
"Rule" : "Whitelisted (Certificate)"
"Rule" : "Allowed (Certificate)"
},
{
"SHA-256" : "295fbc2356e8605e804f95cb6d6f992335e247dbf11767fe8781e2a7f889978a",
"Rule" : "Whitelisted (Certificate)"
"Rule" : "Allowed (Certificate)"
},
{
"SHA-256" : "9f9b36ec79b9fcaf649e17f2f94c544dd408c2ab630e73d7c62a7a43f1bc7b1d",
"Rule" : "Whitelisted (Certificate)"
"Rule" : "Allowed (Certificate)"
},
{
"SHA-256" : "08a09d2d9bade16872acdf5da1c4e9d29582ed985480a9e73fd389e98293c40d",
"Rule" : "Whitelisted (Certificate)"
"Rule" : "Allowed (Certificate)"
},
{
"SHA-256" : "48e4b938b363201ec11d06a13d8080c1bd77187d286780259b9304c96edc5324",
"Rule" : "Whitelisted (Certificate)"
"Rule" : "Allowed (Certificate)"
},
{
"SHA-256" : "7dff6291a29fdaf97dad64c0671dc5d1ecc42189bc5daf8ca08e2a3ae06aff95",
"Rule" : "Whitelisted (Certificate)"
"Rule" : "Allowed (Certificate)"
},
{
"SHA-256" : "7cbba457df4c02d6a7fb93046fea0e869732c65a2225bee6f2e8ec290d38c57b",
"Rule" : "Whitelisted (Certificate)"
"Rule" : "Allowed (Certificate)"
},
{
"SHA-256" : "39e894d1705656451f592884a56bcc76e7ffbb9ed2a8b81d5f2878e1c0e68dbe",
"Rule" : "Whitelisted (Certificate)"
"Rule" : "Allowed (Certificate)"
},
{
"SHA-256" : "8555ed4622410aa7b4379041acabf80fe452a90efe3be2697406935ff0d6822e",
"Rule" : "Whitelisted (Certificate)"
"Rule" : "Allowed (Certificate)"
},
{
"SHA-256" : "cee3e29089f8919ee904328904a7492995cfa398b027857fbf8b3e601397b308",
"Rule" : "Whitelisted (Certificate)"
"Rule" : "Allowed (Certificate)"
},
{
"SHA-256" : "da2cfa9fc2cabd41907f9d0931cea79000a19520fe0b3d73fc40537408730e40",
"Rule" : "Whitelisted (Certificate)"
"Rule" : "Allowed (Certificate)"
},
{
"SHA-256" : "73aee02c4761e5501b1fdfa51ccd316bf735017a5cc0a09d5bcc46f4e7112be9",
"Rule" : "Whitelisted (Certificate)"
"Rule" : "Allowed (Certificate)"
},
{
"SHA-256" : "3a1c4ca5a038b42b1fbfca6f9bec25d307a8af40afbe9c48b307372fe8167a2f",
"Rule" : "Whitelisted (Certificate)"
"Rule" : "Allowed (Certificate)"
},
{
"SHA-256" : "9dc8e1c5b6ec49602dd968eb88286e330220233f7cfa6e73fd37fc983a365084",
"Rule" : "Whitelisted (Certificate)"
"Rule" : "Allowed (Certificate)"
},
{
"SHA-256" : "78fd9b8749c2a216ca76ff4541754d4cf5a5e2e8c00710a85c3fdab171486f92",
"Rule" : "Whitelisted (Certificate)"
"Rule" : "Allowed (Certificate)"
},
{
"SHA-256" : "c4daaf12bd42adee60549872126e15186c75d89e760f078bfa6a45a861f6400f",
"Rule" : "Whitelisted (Certificate)"
"Rule" : "Allowed (Certificate)"
},
{
"SHA-256" : "9dba1cbb01bce47a9610a40cbcbc27704a754e31a889503eb0670c3a25f7ad72",
"Rule" : "Whitelisted (Certificate)"
"Rule" : "Allowed (Certificate)"
},
{
"SHA-256" : "a5ae86cd413589d9661fc604349fb153c0d6f5dfa3d9e95e01b8bc5e09bc1da1",
"Rule" : "Whitelisted (Certificate)"
"Rule" : "Allowed (Certificate)"
},
{
"SHA-256" : "a5ae86cd413589d9661fc604349fb153c0d6f5dfa3d9e95e01b8bc5e09bc1da1",
"Rule" : "Whitelisted (Certificate)"
"Rule" : "Allowed (Certificate)"
},
{
"SHA-256" : "c4c5517ff40a33006028853a19734d8cda8e2942cb9ba27b8310e07f18677487",
"Rule" : "Whitelisted (Certificate)"
"Rule" : "Allowed (Certificate)"
},
{
"SHA-256" : "a944b104742db59204b45f1dae657bd6a845ff2374e1ade3cf9f09cc428154cf",
"Rule" : "Whitelisted (Certificate)"
"Rule" : "Allowed (Certificate)"
},
{
"SHA-256" : "09e143cf3b6c4dcc98676cc45543613b83b6527b502d4dacb42b3f6c7036ef5a",
"Rule" : "Whitelisted (Certificate)"
"Rule" : "Allowed (Certificate)"
},
{
"SHA-256" : "47cea771e93aff464f1060a6a1a2c3855401e6cd22c3971b2b76fae92e8c33b4",
"Rule" : "Whitelisted (Certificate)"
"Rule" : "Allowed (Certificate)"
},
{
"SHA-256" : "5682f15628ae15e5c29aa37f19ec421bbe4aca47734864b6363b73a16f891888",
"Rule" : "Whitelisted (Certificate)"
"Rule" : "Allowed (Certificate)"
},
{
"SHA-256" : "83c29a2445d84daf51eebd51668753fb39600a136efc20aba7298a812b44974c",
"Rule" : "Whitelisted (Certificate)"
"Rule" : "Allowed (Certificate)"
},
{
"SHA-256" : "83929910d3cd2c401636337fadc747a9a8ea6c174bfd80f1e96b99d877ddfa6e",
"Rule" : "Whitelisted (Certificate)"
"Rule" : "Allowed (Certificate)"
},
{
"SHA-256" : "cccd818698aa802b116586a773643d0b951067dea8284304acaae62ac97b362b",
"Rule" : "Whitelisted (Certificate)"
"Rule" : "Allowed (Certificate)"
},
{
"SHA-256" : "2bf2d10a7529a88d340ce0255da52dbef9873ccb44e46d23af03abf70b8e54ca",
"Rule" : "Whitelisted (Certificate)"
"Rule" : "Allowed (Certificate)"
},
{
"SHA-256" : "956f2dc7ba31663dd3a9b70e84e6a2491980165426b90cacd10db4bd010c3353",
"Rule" : "Whitelisted (Certificate)"
"Rule" : "Allowed (Certificate)"
},
{
"SHA-256" : "da1a3ae959751b211928f175f6c8987408a976be44690022c92d45ef5a8cb6e5",
"Rule" : "Whitelisted (Certificate)"
"Rule" : "Allowed (Certificate)"
},
{
"SHA-256" : "1e51209ae4549a72432ad504341c0731a282b33ba99c5f7f4e2abc9993e09b0a",
"Rule" : "Whitelisted (Certificate)"
"Rule" : "Allowed (Certificate)"
},
{
"SHA-256" : "7dff6291a29fdaf97dad64c0671dc5d1ecc42189bc5daf8ca08e2a3ae06aff95",
"Rule" : "Whitelisted (Certificate)"
"Rule" : "Allowed (Certificate)"
},
{
"SHA-256" : "5d8e161c21fc1a43374c4cf21be05360dbe2ecea0165fd4725ae7a958f2a0b02",
"Rule" : "Whitelisted (Certificate)"
"Rule" : "Allowed (Certificate)"
},
{
"SHA-256" : "83929910d3cd2c401636337fadc747a9a8ea6c174bfd80f1e96b99d877ddfa6e",
"Rule" : "Whitelisted (Certificate)"
"Rule" : "Allowed (Certificate)"
},
{
"SHA-256" : "17372eafbe9e920d5715a9cffa59f881ef4ed949785c1e2adf9c067d550dbde6",
"Rule" : "Whitelisted (Certificate)"
"Rule" : "Allowed (Certificate)"
},
{
"SHA-256" : "b1834d55b76c65d57cef1219a30331452301e84b6e315f2a17e5b5b295ce1648",
"Rule" : "Whitelisted (Certificate)"
"Rule" : "Allowed (Certificate)"
}
]
```
@@ -321,37 +328,37 @@ Recursive lookups of an application or directory is a soon to be added feature
{
"SHA-256" : "c149c10c83abaf6b602401106f098b68d47a1a433ab02455cef2ca8057cf4a82",
"Type" : "Unknown",
"Rule" : "Whitelisted (Scope)"
"Rule" : "Allowed (Scope)"
},
{
"SHA-256" : "c339c3e5e04c732ae493dbc4a26d18fccc8bb48cea0cc0762ccd8754ef318a0b",
"Type" : "Unknown",
"Rule" : "Whitelisted (Scope)"
"Rule" : "Allowed (Scope)"
},
{
"SHA-256" : "6ee757ab65d7c93e8b6a467b44cd2f0d10b6db7da8b6200e778c3ca279ea5619",
"Type" : "Executable (x86-64)",
"Rule" : "Whitelisted (Certificate)"
"Rule" : "Allowed (Certificate)"
},
{
"SHA-256" : "82502191c9484b04d685374f9879a0066069c49b8acae7a04b01d38d07e8eca0",
"Type" : "Unknown",
"Rule" : "Whitelisted (Scope)"
"Rule" : "Allowed (Scope)"
},
{
"SHA-256" : "9814019f865a540d3635012a75db932eaefc9a62468750f2294350690430aadf",
"Type" : "Unknown",
"Rule" : "Whitelisted (Scope)"
"Rule" : "Allowed (Scope)"
},
{
"SHA-256" : "05a9c9dbbf0a7a30f083e3dccd8db3d96845e0644930977b4e284c65083b89ac",
"Type" : "Unknown",
"Rule" : "Whitelisted (Scope)"
"Rule" : "Allowed (Scope)"
},
{
"SHA-256" : "e1db8fdffc5017684f962c51fad059dcaa06ab5d551186aa85711f80b727d23d",
"Type" : "Unknown",
"Rule" : "Whitelisted (Scope)"
"Rule" : "Allowed (Scope)"
}
]
```
@@ -366,11 +373,15 @@ The sync command is covered in the [syncing.md](syncing.md) document.
##### Debug Commands
There are a few commands that are not included in the release versions of Santa. They are mainly used during development and only accessible with a debug build of Santa.
There are a few commands that are not included in the release versions of Santa.
They are mainly used during development and only accessible with a debug build
of Santa.
##### bundleinfo
This prints info about all of the executable Mach-O files within a bundle. It also prints the calculated bundle hash for that particular bundle. A bundle hash is a notion used by Santa to represent a set of binaries.
This prints info about all of the executable Mach-O files within a bundle. It
also prints the calculated bundle hash for that particular bundle. A bundle hash
is a notion used by Santa to represent a set of binaries.
```sh
⇒ santactl bundleinfo /Applications/Hex\ Fiend.app
@@ -378,24 +389,26 @@ Hashing time: 12 ms
4 events found
BundleHash: 33da3e2d5e2ccbdb9d34fb9753c2c18805e6325853d2fb4eb947915c90113efc
BundleID: com.ridiculousfish.HexFiend
SHA-256: e592a7c65f803675c0b7d55ab7d2a1a2696c9f097a99dc28a4083d7387e53d95
Path: /Applications/Hex Fiend.app/Contents/Library/LaunchServices/com.ridiculousfish.HexFiend.PrivilegedHelper
SHA-256: e592a7c65f803675c0b7d55ab7d2a1a2696c9f097a99dc28a4083d7387e53d95
Path: /Applications/Hex Fiend.app/Contents/Library/LaunchServices/com.ridiculousfish.HexFiend.PrivilegedHelper
BundleID: com.ridiculousfish.HexFiend
SHA-256: ce23d39a1a8ff2b42baad5a0204b24b57590bb7ff74c9552b3ba10d9c1517279
Path: /Applications/Hex Fiend.app/Contents/Frameworks/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/MacOS/Autoupdate
SHA-256: ce23d39a1a8ff2b42baad5a0204b24b57590bb7ff74c9552b3ba10d9c1517279
Path: /Applications/Hex Fiend.app/Contents/Frameworks/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/MacOS/Autoupdate
BundleID: com.ridiculousfish.HexFiend
SHA-256: efaf88db065beae61615f6f176c11c751555d2bad3c5da6cdad71635896014f1
Path: /Applications/Hex Fiend.app/Contents/MacOS/Hex Fiend
SHA-256: efaf88db065beae61615f6f176c11c751555d2bad3c5da6cdad71635896014f1
Path: /Applications/Hex Fiend.app/Contents/MacOS/Hex Fiend
BundleID: com.ridiculousfish.HexFiend
SHA-256: 148d6ae55176b619e5eb9f5000922b3ca4c126206fc5782f925d112027f9db3c
Path: /Applications/Hex Fiend.app/Contents/Frameworks/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/MacOS/fileop
SHA-256: 148d6ae55176b619e5eb9f5000922b3ca4c126206fc5782f925d112027f9db3c
Path: /Applications/Hex Fiend.app/Contents/Frameworks/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/MacOS/fileop
```
See the [santabs.md](santabs.md) document for more information on bundles and bundle hashes.
See the [santabs.md](santabs.md) document for more information on bundles and
bundle hashes.
##### checkcache
This is used to check if a particular file is apart of santa-driver's kernel cache. Mainly for debugging purposes.
This is used to check if a particular file is apart of santa-driver's kernel
cache. Mainly for debugging purposes.
```sh
⇒ santactl checkcache /usr/bin/yes
@@ -408,7 +421,7 @@ y
y
^C
⇒ santactl checkcache /usr/bin/yes
File exists in [whitelist] kernel cache
File exists in [allowlist] kernel cache
```
##### flushcache
@@ -417,7 +430,7 @@ This can be used to flush santa-driver's kernel cache, as shown here.
```sh
⇒ santactl checkcache /usr/bin/yes
File exists in [whitelist] kernel cache
File exists in [allowlist] kernel cache
⇒ sudo santactl flushcache
Cache flush requested
⇒ santactl checkcache /usr/bin/yes

View File

@@ -1,23 +1,41 @@
# santad
The santad process does the heavy lifting when it comes to making decisions about binary executions. It also handles brokering all of the XPC connections between the various components of Santa. It does all of this with performance being at the forefront.
The santad process does the heavy lifting when it comes to making decisions
about binary executions. It also handles brokering all of the XPC connections
between the various components of Santa. It does all of this with performance
being at the forefront.
##### A note on performance
On an idling machine, santad and the other components of Santa consume virtually no CPU and a minimal amount of memory (5-50MB). When lots of processes `execve()` at the same time, the CPU and memory usage can spike. All of the `execve()` decisions are made on high priority threads to ensure decisions are posted back to the kernel as soon as possible. A watchdog thread will log warnings when sustained high CPU (>20%) and memory (>250MB) usage by santad is detected.
On an idling machine, santad and the other components of Santa consume virtually
no CPU and a minimal amount of memory (5-50MB). When lots of processes
`execve()` at the same time, the CPU and memory usage can spike. All of the
`execve()` decisions are made on high priority threads to ensure decisions are
posted back to the kernel as soon as possible. A watchdog thread will log
warnings when sustained high CPU (>20%) and memory (>250MB) usage by santad is
detected.
##### On Launch
The very first thing santad does once it has been launched is to load and connect to santa-driver. Only one connection may be active at any given time.
The very first thing santad does once it has been launched is to load and
connect to santa-driver. Only one connection may be active at any given time.
At this point, santa-driver is loaded and running in the kernel, but is allowing all executions and not sending any messages to santad. Before santad tells santa-driver it is ready to receive messages, it needs to setup a few more things:
At this point, santa-driver is loaded and running in the kernel, but is allowing
all executions and not sending any messages to santad. Before santad tells
santa-driver it is ready to receive messages, it needs to setup a few more
things:
* The rule and event databases are initialized
* Connections to Santa (GUI) and santactl sync daemon are established.
* The config file is processed.
* The rule and event databases are initialized
* Connections to Santa (GUI) and santactl sync daemon are established.
* The config file is processed.
santad is now ready to start processing decision and logging messages from santa-driver. The listeners are started and santad sits in a run loop awaiting messages from santa-driver.
santad is now ready to start processing decision and logging messages from
santa-driver. The listeners are started and santad sits in a run loop awaiting
messages from santa-driver.
##### Running
Messages are read from a shared memory queue (`IODataQueueMemory` ) on a single thread. A callback is invoked for each message. The callback then dispatches all the work of processing a decision message to a concurrent high priority queue. The log messages are dispatched to a low priority queue for processing.
Messages are read from a shared memory queue (`IODataQueueMemory` ) on a single
thread. A callback is invoked for each message. The callback then dispatches all
the work of processing a decision message to a concurrent high priority queue.
The log messages are dispatched to a low priority queue for processing.

View File

@@ -1,27 +1,38 @@
# Scopes
In addition to rules, Santa can whitelist or blacklist based on scopes. Currently, only a few scopes are implemented. They fall into one of two categories: a whitelist scope or blacklist scope. Scopes are evaluated after rules, with blacklist evaluation preceding whitelist.
In addition to rules, Santa can allow or block based on scopes. Currently, only
a few scopes are implemented. Scopes are evaluated after rules, with block
evaluation preceding allow.
Scopes are a broader way of whitelisting or blacklisting `execve()`s.
Scopes are a broader way of allowing or blocking `execve()`s.
For configuration of scopes see [configuration.md](../deployment/configuration.md).
For configuration of scopes see
[configuration.md](../deployment/configuration.md).
##### Blacklist Scopes
##### Block Scopes
| Scope | Configurable |
| -------------------- | ------------ |
| Blacklist Path Regex | Yes |
| Missing __PAGEZERO | Yes |
Scope | Configurable
------------------ | ------------
Blocked Path Regex | Yes
Missing __PAGEZERO | Yes
##### Whitelist Scopes
##### Allow Scopes
| Scope | Configurable |
| -------------------- | ------------ |
| Whitelist Path Regex | Yes |
| Not a Mach-O | No |
Scope | Configurable
------------------ | ------------
Allowed Path Regex | Yes
Not a Mach-O | No
As seen above, Santa will whitelist any non Mach-O binary under a whitelist scope. However, a blacklist regex or binary SHA-256 rule can be used to block non Mach-O `execve()`s since they are evaluated before the whitelist scopes.
As seen above, Santa will allow any non Mach-O binary under an allow scope.
However, a blocked path regex or binary SHA-256 rule can be used to block non
Mach-O `execve()`s since they are evaluated before the allow scope.
##### Regex Caveats
The paths covered by the whitelist and blacklist regex patterns are not tracked. If an `execve()` is allowed initially, then moved into a blacklist directory, Santa has no knowledge of that move. Since santa-driver caches decisions, the recently moved file will continue to be allowed to `execve()` even though it is now within a blacklisted regex path. The cache holds "allow" decisions until invalidated and "deny" decisions for 500 milliseconds. Going from a blacklist path to a whitelist path is not largely affected.
The paths covered by the allowed path and blocked path regex patterns are not
tracked. If an `execve()` is allowed initially, then moved into a blocked
directory, Santa has no knowledge of that move. Since `santa-driver` caches
decisions, the recently moved file will continue to be allowed to `execve()`
even though it is now within a blocked path. The cache holds "allow" decisions
until invalidated and block decisions for 500 milliseconds. Going from a blocked
path to an allowed path is not largely affected.

View File

@@ -1,8 +1,8 @@
# Building
Santa uses [Bazel](https://bazel.build) for building, testing and releases.
The `master` branch on GitHub is the source-of-truth with features developed
in personal forks.
Santa uses [Bazel](https://bazel.build) for building, testing and releases. The
`master` branch on GitHub is the source-of-truth with features developed in
personal forks.
#### Cloning
@@ -43,15 +43,15 @@ bazel build //Source/santa_driver -c opt
The output for these commands will be a `santa-driver.zip` file under
`bazel-bin` which, when extracted, will contain all of Santa and should be
installed under `/Library/Extensions`. However, if you're working on Santa
and want a quick way to reload everything, see the next section.
installed under `/Library/Extensions`. However, if you're working on Santa and
want a quick way to reload everything, see the next section.
#### Running
When working on Santa, it's useful to have a way to quickly reload all of the
Santa components. For this reason, there's a special rule in the Santa BUILD
file that will compile a new santa-driver, unload Santa if it's running,
install the new Santa in the right place and attempt to load it.
file that will compile a new santa-driver, unload Santa if it's running, install
the new Santa in the right place and attempt to load it.
On macOS 10.11+ System Integrity Protection (SIP) prevents loading of kernel
extensions that are not signed by an Apple KEXT signing certificate. To be able
@@ -61,10 +61,10 @@ to allow non-Apple KEXT signing certificates.
__This is only to be done a machine that is actively developing, unloading and
loading kernel extensions.__
1. Boot into Recovery Mode: Reboot and hold down `command+r`
2. From the utilities menu select `Terminal`
3. Disable the KEXT feature of SIP: `csrutil enable --without kext`
4. Reboot
1. Boot into Recovery Mode: Reboot and hold down `command+r`
2. From the utilities menu select `Terminal`
3. Disable the KEXT feature of SIP: `csrutil enable --without kext`
4. Reboot
You should now be able to load and run a non-release version of Santa.
@@ -83,9 +83,9 @@ bazel run :reload -c opt
#### Using Xcode
While Bazel is a very convenient and powerful build system, it can still be
useful to use Xcode for actually working on the code. If you'd like to use
Xcode you can use [Tulsi](https://tulsi.bazel.build) to generate an `.xcodeproj`
from the BUILD file which will use Bazel for actually doing the builds.
useful to use Xcode for actually working on the code. If you'd like to use Xcode
you can use [Tulsi](https://tulsi.bazel.build) to generate an `.xcodeproj` from
the BUILD file which will use Bazel for actually doing the builds.
#### Debugging
@@ -93,31 +93,31 @@ Xcode and lldb can be used to debug Santa, similarly to any other project, with
some exceptions. Instead of clicking the play button to launch and attach to a
process, you can attach to an already running, or soon to by running, component
of Santa. To do this select the Debug menu and choose `Attach to Process by PID
or Name… `. Below are the four components of Santa and who to debug the process
or Name…`. Below are the four components of Santa and who to debug the process
as.
Note: santa-driver (the kernel extension) cannot be debugged by attaching with
Xcode.
Note: Xcode can attach to santad without interruption, however any breakpoints
in the decision making codepath can deadlock the machine. Using lldb directly
to attach to santad will deadlock the machine.
in the decision making codepath can deadlock the machine. Using lldb directly to
attach to santad will deadlock the machine.
| process | user |
| -------- | ---- |
| santad | root |
| Santa* | me |
| santactl | me |
| santabs | root |
process | user
-------- | ----
santad | root
Santa* | me
santactl | me
santabs | root
Xcode will then wait for the process to start. Issue this command to restart
all the Santa processes in debug mode.
Xcode will then wait for the process to start. Issue this command to restart all
the Santa processes in debug mode.
*The Santa (GUI) process is the only component of Santa that can be launched
and debugged from Xcode directly. All the other components are launched with
*The Santa (GUI) process is the only component of Santa that can be launched and
debugged from Xcode directly. All the other components are launched with
privileges and/or are scoped to an XPC service that launchd scopes to a hosting
bundle. Thus the need for the `Attach to Process by PID or Name…` technique.
See the [ipc](../details/ipc.md) document for for details.
bundle. Thus the need for the `Attach to Process by PID or Name…` technique. See
the [ipc](../details/ipc.md) document for for details.
```sh
bazel run :reload

Some files were not shown because too many files have changed in this diff Show More