Skip to content

Commit

Permalink
Merge branch 'main' into markowsky/add-cs-invalidated-event
Browse files Browse the repository at this point in the history
  • Loading branch information
pmarkowsky authored Oct 31, 2023
2 parents b49aea2 + 64bb34b commit b2265e4
Show file tree
Hide file tree
Showing 20 changed files with 513 additions and 88 deletions.
15 changes: 9 additions & 6 deletions .github/workflows/e2e.yml
Original file line number Diff line number Diff line change
@@ -1,25 +1,28 @@
name: E2E

on: workflow_dispatch
on:
schedule:
- cron: '0 4 * * *' # Every day at 4:00 UTC (not to interfere with fuzzing)
workflow_dispatch:

jobs:
start_vm:
runs-on: e2e-host
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # ratchet:actions/checkout@v3
- name: Start VM
run: python3 Testing/integration/actions/start_vm.py macOS_12.bundle.tar.gz
run: python3 Testing/integration/actions/start_vm.py macOS_14.bundle.tar.gz

integration:
runs-on: e2e-vm
env:
VM_PASSWORD: ${{ secrets.VM_PASSWORD }}
steps:
- uses: actions/checkout@v3
- name: Install configuration profile
run: bazel run //Testing/integration:install_profile -- Testing/integration/configs/default.mobileconfig
- uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # ratchet:actions/checkout@v3
- name: Add homebrew to PATH
run: echo "/opt/homebrew/bin/" >> $GITHUB_PATH
- name: Install configuration profile
run: bazel run //Testing/integration:install_profile -- Testing/integration/configs/default.mobileconfig
- name: Build, install, and start moroz
run: |
bazel build @com_github_groob_moroz//cmd/moroz:moroz
Expand Down
6 changes: 6 additions & 0 deletions Source/common/SNTCommonEnums.h
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,12 @@ typedef NS_ENUM(NSInteger, SNTOverrideFileAccessAction) {
SNTOverrideFileAccessActionDiable,
};

typedef NS_ENUM(NSInteger, SNTDeviceManagerStartupPreferences) {
SNTDeviceManagerStartupPreferencesNone,
SNTDeviceManagerStartupPreferencesUnmount,
SNTDeviceManagerStartupPreferencesForceUnmount,
};

#ifdef __cplusplus
enum class FileAccessPolicyDecision {
kNoPolicy,
Expand Down
14 changes: 14 additions & 0 deletions Source/common/SNTConfigurator.h
Original file line number Diff line number Diff line change
Expand Up @@ -454,6 +454,20 @@
///
@property(nonatomic) NSArray<NSString *> *remountUSBMode;

///
/// If set, defines the action that should be taken on existing USB mounts when
/// Santa starts up.
///
/// Supported values are:
/// * "Unmount": Unmount mass storage devices
/// * "ForceUnmount": Force unmount mass storage devices
///
///
/// Note: Existing mounts with mount flags that are a superset of RemountUSBMode
/// are unaffected and left mounted.
///
@property(readonly, nonatomic) SNTDeviceManagerStartupPreferences onStartUSBOptions;

///
/// If set, will override the action taken when a file access rule violation
/// occurs. This setting will apply across all rules in the file access policy.
Expand Down
14 changes: 14 additions & 0 deletions Source/common/SNTConfigurator.m
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ @implementation SNTConfigurator
static NSString *const kFailClosedKey = @"FailClosed";
static NSString *const kBlockUSBMountKey = @"BlockUSBMount";
static NSString *const kRemountUSBModeKey = @"RemountUSBMode";
static NSString *const kOnStartUSBOptions = @"OnStartUSBOptions";
static NSString *const kEnableTransitiveRulesKey = @"EnableTransitiveRules";
static NSString *const kEnableTransitiveRulesKeyDeprecated = @"EnableTransitiveWhitelisting";
static NSString *const kAllowedPathRegexKey = @"AllowedPathRegex";
Expand Down Expand Up @@ -181,6 +182,7 @@ - (instancetype)init {
kBlockedPathRegexKeyDeprecated : re,
kBlockUSBMountKey : number,
kRemountUSBModeKey : array,
kOnStartUSBOptions : string,
kEnablePageZeroProtectionKey : number,
kEnableBadSignatureProtectionKey : number,
kEnableSilentModeKey : number,
Expand Down Expand Up @@ -635,6 +637,18 @@ - (void)setRemountUSBMode:(NSArray<NSString *> *)args {
return args;
}

- (SNTDeviceManagerStartupPreferences)onStartUSBOptions {
NSString *action = [self.configState[kOnStartUSBOptions] lowercaseString];

if ([action isEqualToString:@"unmount"]) {
return SNTDeviceManagerStartupPreferencesUnmount;
} else if ([action isEqualToString:@"forceunmount"]) {
return SNTDeviceManagerStartupPreferencesForceUnmount;
} else {
return SNTDeviceManagerStartupPreferencesNone;
}
}

- (NSDictionary<NSString *, SNTRule *> *)staticRules {
return self.cachedStaticRules;
}
Expand Down
2 changes: 2 additions & 0 deletions Source/santactl/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,8 @@ santa_unit_test(
"//Source/common:SNTFileInfo",
"//Source/common:SNTLogging",
"//Source/common:SNTRule",
"//Source/common:SNTStoredEvent",
"//Source/common:SNTXPCBundleServiceInterface",
"//Source/common:SNTXPCControlInterface",
"@MOLCertificate",
"@MOLCodesignChecker",
Expand Down
91 changes: 91 additions & 0 deletions Source/santactl/Commands/SNTCommandFileInfo.m
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
#import "Source/common/SNTFileInfo.h"
#import "Source/common/SNTLogging.h"
#import "Source/common/SNTRule.h"
#import "Source/common/SNTStoredEvent.h"
#import "Source/common/SNTXPCBundleServiceInterface.h"
#import "Source/common/SNTXPCControlInterface.h"
#import "Source/santactl/SNTCommand.h"
#import "Source/santactl/SNTCommandController.h"
Expand Down Expand Up @@ -55,6 +57,13 @@
static NSString *const kSHA256 = @"SHA-256";
static NSString *const kSHA1 = @"SHA-1";

// bundle info keys
static NSString *const kBundleInfo = @"Bundle Info";
static NSString *const kBundlePath = @"Main Bundle Path";
static NSString *const kBundleID = @"Main Bundle ID";
static NSString *const kBundleHash = @"Bundle Hash";
static NSString *const kBundleHashes = @"Bundle Hashes";

// Message displayed when daemon communication fails
static NSString *const kCommunicationErrorMsg = @"Could not communicate with daemon";

Expand All @@ -72,6 +81,7 @@ @interface SNTCommandFileInfo : SNTCommand <SNTCommandProtocol>
// Properties set from commandline flags
@property(nonatomic) BOOL recursive;
@property(nonatomic) BOOL jsonOutput;
@property(nonatomic) BOOL bundleInfo;
@property(nonatomic) NSNumber *certIndex;
@property(nonatomic, copy) NSArray<NSString *> *outputKeyList;
@property(nonatomic, copy) NSDictionary<NSString *, NSRegularExpression *> *outputFilters;
Expand Down Expand Up @@ -156,6 +166,7 @@ + (NSString *)longHelpText {
@"\n"
@"Usage: santactl fileinfo [options] [file-paths]\n"
@" --recursive (-r): Search directories recursively.\n"
@" Incompatible with --bundleinfo.\n"
@" --json: Output in JSON format.\n"
@" --key: Search and return this one piece of information.\n"
@" You may specify multiple keys by repeating this flag.\n"
Expand All @@ -167,12 +178,16 @@ + (NSString *)longHelpText {
@" signing chain to show info only for that certificate.\n"
@" 0 up to n for the leaf certificate up to the root\n"
@" -1 down to -n-1 for the root certificate down to the leaf\n"
@" Incompatible with --bundleinfo."
@"\n"
@" --filter: Use predicates of the form 'key=regex' to filter out which files\n"
@" are displayed. Valid keys are the same as for --key. Value is a\n"
@" case-insensitive regular expression which must match anywhere in\n"
@" the keyed property value for the file's info to be displayed.\n"
@" You may specify multiple filters by repeating this flag.\n"
@" --bundleinfo: If the file is part of a bundle, will also display bundle\n"
@" hash information and hashes of all bundle executables.\n"
@" Incompatible with --recursive and --cert-index.\n"
@"\n"
@"Examples: santactl fileinfo --cert-index 1 --key SHA-256 --json /usr/bin/yes\n"
@" santactl fileinfo --key SHA-256 --json /usr/bin/yes\n"
Expand Down Expand Up @@ -682,6 +697,48 @@ - (void)printInfoForFile:(NSString *)path {
if (outputDict[key]) continue; // ignore keys that we've already set due to a filter
outputDict[key] = self.propertyMap[key](self, fileInfo);
}

if (self.bundleInfo) {
SNTStoredEvent *se = [[SNTStoredEvent alloc] init];
se.fileBundlePath = fileInfo.bundlePath;

MOLXPCConnection *bc = [SNTXPCBundleServiceInterface configuredConnection];
[bc resume];

__block NSMutableDictionary *bundleInfo = [[NSMutableDictionary alloc] init];

bundleInfo[kBundlePath] = fileInfo.bundle.bundlePath;
bundleInfo[kBundleID] = fileInfo.bundle.bundleIdentifier;

dispatch_semaphore_t sema = dispatch_semaphore_create(0);

[[bc remoteObjectProxy]
hashBundleBinariesForEvent:se
reply:^(NSString *hash, NSArray<SNTStoredEvent *> *events,
NSNumber *time) {
bundleInfo[kBundleHash] = hash;

NSMutableArray *bundleHashes = [[NSMutableArray alloc] init];

for (SNTStoredEvent *event in events) {
[bundleHashes
addObject:@{kSHA256 : event.fileSHA256, kPath : event.filePath}];
}

bundleInfo[kBundleHashes] = bundleHashes;
[[bc remoteObjectProxy] spindown];
dispatch_semaphore_signal(sema);
}];

int secondsToWait = 30;
if (dispatch_semaphore_wait(sema,
dispatch_time(DISPATCH_TIME_NOW, secondsToWait * NSEC_PER_SEC))) {
fprintf(stderr, "The bundle service did not finish collecting hashes within %d seconds\n",
secondsToWait);
}

outputDict[kBundleInfo] = bundleInfo;
}
}

// If there's nothing in the outputDict, then don't need to print anything.
Expand Down Expand Up @@ -710,6 +767,11 @@ - (void)printInfoForFile:(NSString *)path {
}
}
}

if (self.bundleInfo) {
[output appendString:[self stringForBundleInfo:outputDict[kBundleInfo] key:kBundleInfo]];
}

if (!singleKey) [output appendString:@"\n"];
}

Expand Down Expand Up @@ -739,6 +801,9 @@ - (NSArray *)parseArguments:(NSArray<NSString *> *)arguments {
if ([arg caseInsensitiveCompare:@"--json"] == NSOrderedSame) {
self.jsonOutput = YES;
} else if ([arg caseInsensitiveCompare:@"--cert-index"] == NSOrderedSame) {
if (self.bundleInfo) {
[self printErrorUsageAndExit:@"\n--cert-index is incompatible with --bundleinfo"];
}
i += 1; // advance to next argument and grab index
if (i >= nargs || [arguments[i] hasPrefix:@"--"]) {
[self printErrorUsageAndExit:@"\n--cert-index requires an argument"];
Expand Down Expand Up @@ -788,7 +853,17 @@ - (NSArray *)parseArguments:(NSArray<NSString *> *)arguments {
filters[key] = regex;
} else if ([arg caseInsensitiveCompare:@"--recursive"] == NSOrderedSame ||
[arg caseInsensitiveCompare:@"-r"] == NSOrderedSame) {
if (self.bundleInfo) {
[self printErrorUsageAndExit:@"\n--recursive is incompatible with --bundleinfo"];
}
self.recursive = YES;
} else if ([arg caseInsensitiveCompare:@"--bundleinfo"] == NSOrderedSame ||
[arg caseInsensitiveCompare:@"-b"] == NSOrderedSame) {
if (self.recursive || self.certIndex) {
[self printErrorUsageAndExit:
@"\n--bundleinfo is incompatible with --recursive and --cert-index"];
}
self.bundleInfo = YES;
} else {
[paths addObject:arg];
}
Expand Down Expand Up @@ -868,6 +943,22 @@ - (NSString *)stringForSigningChain:(NSArray *)signingChain key:(NSString *)key
return result.copy;
}

- (NSString *)stringForBundleInfo:(NSDictionary *)bundleInfo key:(NSString *)key {
NSMutableString *result = [NSMutableString string];

[result appendFormat:@"%@:\n", key];

[result appendFormat:@" %-20s: %@\n", kBundlePath.UTF8String, bundleInfo[kBundlePath]];
[result appendFormat:@" %-20s: %@\n", kBundleID.UTF8String, bundleInfo[kBundleID]];
[result appendFormat:@" %-20s: %@\n", kBundleHash.UTF8String, bundleInfo[kBundleHash]];

for (NSDictionary *hashPath in bundleInfo[kBundleHashes]) {
[result appendFormat:@" %@ %@\n", hashPath[kSHA256], hashPath[kPath]];
}

return [result copy];
}

- (NSString *)stringForCertificate:(NSDictionary *)cert withKeys:(NSArray *)keys index:(int)index {
if (!cert) return @"";
NSMutableString *result = [NSMutableString string];
Expand Down
2 changes: 2 additions & 0 deletions Source/santad/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,7 @@ objc_library(
":Metrics",
":SNTEndpointSecurityClient",
":SNTEndpointSecurityEventHandler",
"//Source/common:SNTCommonEnums",
"//Source/common:SNTDeviceEvent",
"//Source/common:SNTLogging",
],
Expand Down Expand Up @@ -1317,6 +1318,7 @@ santa_unit_test(
":Metrics",
":MockEndpointSecurityAPI",
":SNTEndpointSecurityDeviceManager",
"//Source/common:SNTCommonEnums",
"//Source/common:SNTConfigurator",
"//Source/common:SNTDeviceEvent",
"//Source/common:TestUtils",
Expand Down
25 changes: 25 additions & 0 deletions Source/santad/EventProviders/DiskArbitrationTestUtil.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@
#include <CoreFoundation/CoreFoundation.h>
#include <DiskArbitration/DiskArbitration.h>
#include <Foundation/Foundation.h>
#include <sys/mount.h>
#include <sys/param.h>
#include <sys/ucred.h>

NS_ASSUME_NONNULL_BEGIN

Expand All @@ -27,6 +30,7 @@ NS_ASSUME_NONNULL_BEGIN
@interface MockDADisk : NSObject
@property(nonatomic) NSDictionary *diskDescription;
@property(nonatomic, readwrite) NSString *name;
@property(nonatomic) BOOL wasUnmounted;
@end

typedef void (^MockDADiskAppearedCallback)(DADiskRef ref);
Expand All @@ -49,6 +53,23 @@ typedef void (^MockDADiskAppearedCallback)(DADiskRef ref);
+ (instancetype _Nonnull)mockDiskArbitration;
@end

@interface MockStatfs : NSObject
@property NSString *fromName;
@property NSString *onName;
@property NSNumber *flags;

- (instancetype _Nonnull)initFrom:(NSString *)from on:(NSString *)on flags:(NSNumber *)flags;
@end

@interface MockMounts : NSObject
@property(nonatomic) NSMutableDictionary<NSString *, MockStatfs *> *mounts;

- (instancetype _Nonnull)init;
- (void)reset;
- (void)insert:(MockStatfs *)sfs;
+ (instancetype _Nonnull)mockMounts;
@end

//
// All DiskArbitration functions used in SNTEndpointSecurityDeviceManager
// and shimmed out accordingly.
Expand Down Expand Up @@ -81,5 +102,9 @@ void DARegisterDiskDescriptionChangedCallback(DASessionRef session,
void DASessionSetDispatchQueue(DASessionRef session, dispatch_queue_t __nullable queue);
DASessionRef __nullable DASessionCreate(CFAllocatorRef __nullable allocator);

void DADiskUnmount(DADiskRef disk, DADiskUnmountOptions options,
DADiskUnmountCallback __nullable callback, void *__nullable context);
int getmntinfo_r_np(struct statfs *__nullable *__nullable mntbufp, int flags);

CF_EXTERN_C_END
NS_ASSUME_NONNULL_END
Loading

0 comments on commit b2265e4

Please sign in to comment.