diff --git a/Source/common/SNTCommonEnums.h b/Source/common/SNTCommonEnums.h index 850bc57a3..f571ed880 100644 --- a/Source/common/SNTCommonEnums.h +++ b/Source/common/SNTCommonEnums.h @@ -152,6 +152,12 @@ typedef NS_ENUM(NSInteger, SNTMetricFormatType) { SNTMetricFormatTypeMonarchJSON, }; +typedef NS_ENUM(NSInteger, SNTOverrideFileAccessAction) { + SNTOverrideFileAccessActionNone, + SNTOverrideFileAccessActionAuditOnly, + SNTOverrideFileAccessActionDiable, +}; + #ifdef __cplusplus enum class FileAccessPolicyDecision { kNoPolicy, diff --git a/Source/common/SNTConfigurator.h b/Source/common/SNTConfigurator.h index c90eecaf7..2b838860f 100644 --- a/Source/common/SNTConfigurator.h +++ b/Source/common/SNTConfigurator.h @@ -454,6 +454,25 @@ /// @property(nonatomic) NSArray *remountUSBMode; +/// +/// 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. +/// +/// Possible values are +/// * "AuditOnly": When a rule is violated, it will be logged, but the access +/// will not be blocked +/// * "Disable": No access will be logged or blocked. +/// +/// If not set, no override will take place and the file acces spolicy will +/// apply as configured. +/// +@property(readonly, nonatomic) SNTOverrideFileAccessAction overrideFileAccessAction; + +/// +/// Set the action that will override file access policy config action +/// +- (void)setSyncServerOverrideFileAccessAction:(NSString *)action; + /// /// If set, this over-rides the default machine ID used for syncing. /// diff --git a/Source/common/SNTConfigurator.m b/Source/common/SNTConfigurator.m index 8208294cf..2a3e0753f 100644 --- a/Source/common/SNTConfigurator.m +++ b/Source/common/SNTConfigurator.m @@ -13,7 +13,6 @@ /// limitations under the License. #import "Source/common/SNTConfigurator.h" -#import "Source/common/SNTCommonEnums.h" #include @@ -130,6 +129,7 @@ @implementation SNTConfigurator static NSString *const kBlockedPathRegexKeyDeprecated = @"BlacklistRegex"; static NSString *const kEnableAllEventUploadKey = @"EnableAllEventUpload"; static NSString *const kDisableUnknownEventUploadKey = @"DisableUnknownEventUpload"; +static NSString *const kOverrideFileAccessActionKey = @"OverrideFileAccessAction"; static NSString *const kMetricFormat = @"MetricFormat"; static NSString *const kMetricURL = @"MetricURL"; @@ -166,6 +166,7 @@ - (instancetype)init { kRuleSyncLastSuccess : date, kSyncCleanRequired : number, kEnableAllEventUploadKey : number, + kOverrideFileAccessActionKey : string, }; _forcedConfigKeyTypes = @{ kClientModeKey : number, @@ -236,6 +237,7 @@ - (instancetype)init { kMetricExtraLabels : dictionary, kEnableAllEventUploadKey : number, kDisableUnknownEventUploadKey : number, + kOverrideFileAccessActionKey : string, }; _defaults = [NSUserDefaults standardUserDefaults]; [_defaults addSuiteNamed:@"com.google.santa"]; @@ -519,6 +521,10 @@ + (NSSet *)keyPathsForValuesAffectingUsbBlockMessage { return [self configStateSet]; } ++ (NSSet *)keyPathsForValuesAffectingOverrideFileAccessActionKey { + return [self syncAndConfigStateSet]; +} + #pragma mark Public Interface - (SNTClientMode)clientMode { @@ -951,6 +957,33 @@ - (BOOL)blockUSBMount { return [self.configState[kBlockUSBMountKey] boolValue]; } +- (void)setSyncServerOverrideFileAccessAction:(NSString *)action { + NSString *a = [action lowercaseString]; + if ([a isEqualToString:@"auditonly"] || [a isEqualToString:@"disable"] || + [a isEqualToString:@"none"] || [a isEqualToString:@""]) { + [self updateSyncStateForKey:kOverrideFileAccessActionKey value:action]; + } +} + +- (SNTOverrideFileAccessAction)overrideFileAccessAction { + NSString *action = [self.syncState[kOverrideFileAccessActionKey] lowercaseString]; + + if (!action) { + action = [self.configState[kOverrideFileAccessActionKey] lowercaseString]; + if (!action) { + return SNTOverrideFileAccessActionNone; + } + } + + if ([action isEqualToString:@"auditonly"]) { + return SNTOverrideFileAccessActionAuditOnly; + } else if ([action isEqualToString:@"disable"]) { + return SNTOverrideFileAccessActionDiable; + } else { + return SNTOverrideFileAccessActionNone; + } +} + /// /// Returns YES if all of the necessary options are set to export metrics, NO /// otherwise. diff --git a/Source/common/SNTSyncConstants.h b/Source/common/SNTSyncConstants.h index 866201f80..4e69f7039 100644 --- a/Source/common/SNTSyncConstants.h +++ b/Source/common/SNTSyncConstants.h @@ -54,6 +54,7 @@ extern NSString *const kEnableTransitiveRulesDeprecated; extern NSString *const kEnableTransitiveRulesSuperDeprecated; extern NSString *const kEnableAllEventUpload; extern NSString *const kDisableUnknownEventUpload; +extern NSString *const kOverrideFileAccessAction; extern NSString *const kEvents; extern NSString *const kFileSHA256; diff --git a/Source/common/SNTSyncConstants.m b/Source/common/SNTSyncConstants.m index 6e013a536..f22cb9ae7 100644 --- a/Source/common/SNTSyncConstants.m +++ b/Source/common/SNTSyncConstants.m @@ -47,6 +47,7 @@ NSString *const kFCMToken = @"fcm_token"; NSString *const kFCMFullSyncInterval = @"fcm_full_sync_interval"; NSString *const kFCMGlobalRuleSyncDeadline = @"fcm_global_rule_sync_deadline"; +NSString *const kOverrideFileAccessAction = @"override_file_access_action"; NSString *const kEnableBundles = @"enable_bundles"; NSString *const kEnableBundlesDeprecated = @"bundles_enabled"; diff --git a/Source/common/SNTXPCControlInterface.h b/Source/common/SNTXPCControlInterface.h index 69195eb85..312e43ec2 100644 --- a/Source/common/SNTXPCControlInterface.h +++ b/Source/common/SNTXPCControlInterface.h @@ -53,6 +53,7 @@ - (void)setEnableTransitiveRules:(BOOL)enabled reply:(void (^)(void))reply; - (void)setEnableAllEventUpload:(BOOL)enabled reply:(void (^)(void))reply; - (void)setDisableUnknownEventUpload:(BOOL)enabled reply:(void (^)(void))reply; +- (void)setOverrideFileAccessAction:(NSString *)action reply:(void (^)(void))reply; /// /// Syncd Ops diff --git a/Source/santad/BUILD b/Source/santad/BUILD index 03fc4d1a3..116ba8e6e 100644 --- a/Source/santad/BUILD +++ b/Source/santad/BUILD @@ -1244,6 +1244,7 @@ santa_unit_test( ":WatchItems", "//Source/common:Platform", "//Source/common:SNTCachedDecision", + "//Source/common:SNTCommonEnums", "//Source/common:SNTConfigurator", "//Source/common:TestUtils", "@MOLCertificate", diff --git a/Source/santad/EventProviders/SNTEndpointSecurityFileAccessAuthorizer.mm b/Source/santad/EventProviders/SNTEndpointSecurityFileAccessAuthorizer.mm index 0eb3ff1ae..4724bade9 100644 --- a/Source/santad/EventProviders/SNTEndpointSecurityFileAccessAuthorizer.mm +++ b/Source/santad/EventProviders/SNTEndpointSecurityFileAccessAuthorizer.mm @@ -238,6 +238,40 @@ es_auth_result_t FileAccessPolicyDecisionToESAuthResult(FileAccessPolicyDecision } } +bool IsBlockDecision(FileAccessPolicyDecision decision) { + return decision == FileAccessPolicyDecision::kDenied || + decision == FileAccessPolicyDecision::kDeniedInvalidSignature; +} + +FileAccessPolicyDecision ApplyOverrideToDecision(FileAccessPolicyDecision decision, + SNTOverrideFileAccessAction overrideAction) { + switch (overrideAction) { + // When no override should be applied, return the decision unmodified + case SNTOverrideFileAccessActionNone: return decision; + + // When the decision should be overridden to be audit only, only change the + // decision if it was going to deny the operation. + case SNTOverrideFileAccessActionAuditOnly: + if (IsBlockDecision(decision)) { + return FileAccessPolicyDecision::kAllowedAuditOnly; + } else { + return decision; + } + + // If the override action is to disable policy, return a decision that will + // be treated as if no policy applied to the operation. + case SNTOverrideFileAccessActionDiable: return FileAccessPolicyDecision::kNoPolicy; + + default: + // This is a programming error. Bail. + LOGE(@"Invalid override file access action encountered: %d", + static_cast(overrideAction)); + [NSException + raise:@"Invalid SNTOverrideFileAccessAction" + format:@"Invalid SNTOverrideFileAccessAction: %d", static_cast(overrideAction)]; + } +} + bool ShouldLogDecision(FileAccessPolicyDecision decision) { switch (decision) { case FileAccessPolicyDecision::kDenied: return true; @@ -345,6 +379,7 @@ bool ShouldMessageTTY(const std::shared_ptr &policy, const Mess } @interface SNTEndpointSecurityFileAccessAuthorizer () +@property SNTConfigurator *configurator; @property SNTDecisionCache *decisionCache; @property bool isSubscribed; @end @@ -382,6 +417,8 @@ @implementation SNTEndpointSecurityFileAccessAuthorizer { _ttyWriter = std::move(ttyWriter); _metrics = std::move(metrics); + _configurator = [SNTConfigurator configurator]; + _rateLimiter = RateLimiter::Create(_metrics, santa::santad::Processor::kFileAccessAuthorizer, kDefaultRateLimitQPS); @@ -565,7 +602,7 @@ - (FileAccessPolicyDecision)applyPolicy: // If the process is signed but has an invalid signature, it is denied if (((msg->process->codesigning_flags & (CS_SIGNED | CS_VALID)) == CS_SIGNED) && - [[SNTConfigurator configurator] enableBadSignatureProtection]) { + [self.configurator enableBadSignatureProtection]) { // TODO(mlw): Think about how to make stronger guarantees here to handle // programs becoming invalid after first being granted access. Maybe we // should only allow things that have hardened runtime flags set? @@ -621,10 +658,10 @@ - (FileAccessPolicyDecision)handleMessage:(const Message &)msg target:(const PathTarget &)target policy: (std::optional>)optionalPolicy - policyVersion:(const std::string &)policyVersion { - FileAccessPolicyDecision policyDecision = [self applyPolicy:optionalPolicy - forTarget:target - toMessage:msg]; + policyVersion:(const std::string &)policyVersion + overrideAction:(SNTOverrideFileAccessAction)overrideAction { + FileAccessPolicyDecision policyDecision = ApplyOverrideToDecision( + [self applyPolicy:optionalPolicy forTarget:target toMessage:msg], overrideAction); // Note: If ShouldLogDecision, it shouldn't be possible for optionalPolicy // to not have a value. Performing the check just in case to prevent a crash. @@ -704,7 +741,8 @@ - (FileAccessPolicyDecision)handleMessage:(const Message &)msg return policyDecision; } -- (void)processMessage:(const Message &)msg { +- (void)processMessage:(const Message &)msg + overrideAction:(SNTOverrideFileAccessAction)overrideAction { std::vector targets; targets.reserve(2); PopulatePathTargets(msg, targets); @@ -726,7 +764,8 @@ - (void)processMessage:(const Message &)msg { FileAccessPolicyDecision curDecision = [self handleMessage:msg target:targets[i] policy:versionAndPolicies.second[i] - policyVersion:versionAndPolicies.first]; + policyVersion:versionAndPolicies.first + overrideAction:overrideAction]; policyResult = CombinePolicyResults(policyResult, FileAccessPolicyDecisionToESAuthResult(curDecision)); @@ -751,6 +790,16 @@ - (void)processMessage:(const Message &)msg { - (void)handleMessage:(santa::santad::event_providers::endpoint_security::Message &&)esMsg recordEventMetrics:(void (^)(EventDisposition))recordEventMetrics { + SNTOverrideFileAccessAction overrideAction = [self.configurator overrideFileAccessAction]; + + // If the override action is set to Disable, return immediately. + if (overrideAction == SNTOverrideFileAccessActionDiable) { + if (esMsg->action_type == ES_ACTION_TYPE_AUTH) { + [self respondToMessage:esMsg withAuthResult:ES_AUTH_RESULT_ALLOW cacheable:false]; + } + return; + } + if (esMsg->event_type == ES_EVENT_TYPE_AUTH_OPEN && !(esMsg->event.open.fflag & kOpenFlagsIndicatingWrite)) { if (self->_readsCache.Exists(esMsg->process, ^std::pair { @@ -769,7 +818,7 @@ - (void)handleMessage:(santa::santad::event_providers::endpoint_security::Messag [self processMessage:std::move(esMsg) handler:^(const Message &msg) { - [self processMessage:msg]; + [self processMessage:msg overrideAction:overrideAction]; recordEventMetrics(EventDisposition::kProcessed); }]; } diff --git a/Source/santad/EventProviders/SNTEndpointSecurityFileAccessAuthorizerTest.mm b/Source/santad/EventProviders/SNTEndpointSecurityFileAccessAuthorizerTest.mm index c90d0c3cc..9e6079d05 100644 --- a/Source/santad/EventProviders/SNTEndpointSecurityFileAccessAuthorizerTest.mm +++ b/Source/santad/EventProviders/SNTEndpointSecurityFileAccessAuthorizerTest.mm @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -32,6 +33,7 @@ #include "Source/common/Platform.h" #include "Source/common/SNTCachedDecision.h" +#include "Source/common/SNTCommonEnums.h" #import "Source/common/SNTConfigurator.h" #include "Source/common/TestUtils.h" #include "Source/santad/DataLayer/WatchItemPolicy.h" @@ -60,6 +62,9 @@ extern bool ShouldLogDecision(FileAccessPolicyDecision decision); extern bool ShouldNotifyUserDecision(FileAccessPolicyDecision decision); extern es_auth_result_t CombinePolicyResults(es_auth_result_t result1, es_auth_result_t result2); +extern bool IsBlockDecision(FileAccessPolicyDecision decision); +extern FileAccessPolicyDecision ApplyOverrideToDecision(FileAccessPolicyDecision decision, + SNTOverrideFileAccessAction overrideAction); static inline std::pair FileID(const es_file_t &file) { return std::make_pair(file.stat.st_dev, file.stat.st_ino); @@ -261,6 +266,63 @@ - (void)testShouldNotifyUserDecision { } } +- (void)testIsBlockDecision { + std::map policyDecisionToIsBlockDecision = { + {FileAccessPolicyDecision::kNoPolicy, false}, + {FileAccessPolicyDecision::kDenied, true}, + {FileAccessPolicyDecision::kDeniedInvalidSignature, true}, + {FileAccessPolicyDecision::kAllowed, false}, + {FileAccessPolicyDecision::kAllowedReadAccess, false}, + {FileAccessPolicyDecision::kAllowedAuditOnly, false}, + {(FileAccessPolicyDecision)123, false}, + }; + + for (const auto &kv : policyDecisionToIsBlockDecision) { + XCTAssertEqual(ShouldNotifyUserDecision(kv.first), kv.second); + } +} + +- (void)testApplyOverrideToDecision { + std::map, + FileAccessPolicyDecision> + decisionAndOverrideToDecision = { + // Override action: None - Policy shouldn't be changed + {{FileAccessPolicyDecision::kNoPolicy, SNTOverrideFileAccessActionNone}, + FileAccessPolicyDecision::kNoPolicy}, + {{FileAccessPolicyDecision::kDenied, SNTOverrideFileAccessActionNone}, + FileAccessPolicyDecision::kDenied}, + + // Override action: AuditOnly - Policy should be changed only on blocked decisions + {{FileAccessPolicyDecision::kNoPolicy, SNTOverrideFileAccessActionAuditOnly}, + FileAccessPolicyDecision::kNoPolicy}, + {{FileAccessPolicyDecision::kAllowedAuditOnly, SNTOverrideFileAccessActionAuditOnly}, + FileAccessPolicyDecision::kAllowedAuditOnly}, + {{FileAccessPolicyDecision::kAllowedReadAccess, SNTOverrideFileAccessActionAuditOnly}, + FileAccessPolicyDecision::kAllowedReadAccess}, + {{FileAccessPolicyDecision::kDenied, SNTOverrideFileAccessActionAuditOnly}, + FileAccessPolicyDecision::kAllowedAuditOnly}, + {{FileAccessPolicyDecision::kDeniedInvalidSignature, SNTOverrideFileAccessActionAuditOnly}, + FileAccessPolicyDecision::kAllowedAuditOnly}, + + // Override action: Disable - Always changes the decision to be no policy applied + {{FileAccessPolicyDecision::kAllowed, SNTOverrideFileAccessActionDiable}, + FileAccessPolicyDecision::kNoPolicy}, + {{FileAccessPolicyDecision::kDenied, SNTOverrideFileAccessActionDiable}, + FileAccessPolicyDecision::kNoPolicy}, + {{FileAccessPolicyDecision::kAllowedReadAccess, SNTOverrideFileAccessActionDiable}, + FileAccessPolicyDecision::kNoPolicy}, + {{FileAccessPolicyDecision::kAllowedAuditOnly, SNTOverrideFileAccessActionDiable}, + FileAccessPolicyDecision::kNoPolicy}, + }; + + for (const auto &kv : decisionAndOverrideToDecision) { + XCTAssertEqual(ApplyOverrideToDecision(kv.first.first, kv.first.second), kv.second); + } + + XCTAssertThrows( + ApplyOverrideToDecision(FileAccessPolicyDecision::kAllowed, (SNTOverrideFileAccessAction)123)); +} + - (void)testCombinePolicyResults { // Ensure that the combined result is ES_AUTH_RESULT_DENY if both or either // input result is ES_AUTH_RESULT_DENY. @@ -717,7 +779,7 @@ - (void)testDisable { XCTBubbleMockVerifyAndClearExpectations(mockESApi.get()); } -- (void)testGetPathTargets { +- (void)testPopulatePathTargets { // This test ensures that the `GetPathTargets` functions returns the // expected combination of targets for each handled event variant es_file_t testFile1 = MakeESFile("test_file_1", MakeStat(100)); diff --git a/Source/santad/SNTDaemonControlController.mm b/Source/santad/SNTDaemonControlController.mm index 93a9e808b..6528eae97 100644 --- a/Source/santad/SNTDaemonControlController.mm +++ b/Source/santad/SNTDaemonControlController.mm @@ -252,6 +252,11 @@ - (void)setRemountUSBMode:(NSArray *)remountUSBMode reply:(void (^)(void))reply reply(); } +- (void)setOverrideFileAccessAction:(NSString *)action reply:(void (^)(void))reply { + [[SNTConfigurator configurator] setSyncServerOverrideFileAccessAction:action]; + reply(); +} + - (void)enableBundles:(void (^)(BOOL))reply { reply([SNTConfigurator configurator].enableBundles); } diff --git a/Source/santasyncservice/SNTSyncPostflight.m b/Source/santasyncservice/SNTSyncPostflight.m index dd0b70a09..4f115c1e4 100644 --- a/Source/santasyncservice/SNTSyncPostflight.m +++ b/Source/santasyncservice/SNTSyncPostflight.m @@ -96,6 +96,12 @@ - (BOOL)sync { }]; } + if (self.syncState.overrideFileAccessAction) { + [rop setOverrideFileAccessAction:self.syncState.overrideFileAccessAction + reply:^{ + }]; + } + // Update last sync success [rop setFullSyncLastSuccess:[NSDate date] reply:^{ diff --git a/Source/santasyncservice/SNTSyncPreflight.m b/Source/santasyncservice/SNTSyncPreflight.m index 5b9cc3c6d..7a9f416e1 100644 --- a/Source/santasyncservice/SNTSyncPreflight.m +++ b/Source/santasyncservice/SNTSyncPreflight.m @@ -134,6 +134,9 @@ - (BOOL)sync { self.syncState.blockUSBMount = EnsureType(resp[kBlockUSBMount], [NSNumber class]); self.syncState.remountUSBMode = EnsureType(resp[kRemountUSBMode], [NSArray class]); + self.syncState.overrideFileAccessAction = + EnsureType(resp[kOverrideFileAccessAction], [NSString class]); + if ([EnsureType(resp[kCleanSync], [NSNumber class]) boolValue]) { SLOGD(@"Clean sync requested by server"); self.syncState.cleanSync = YES; diff --git a/Source/santasyncservice/SNTSyncState.h b/Source/santasyncservice/SNTSyncState.h index 199783949..9a1844680 100644 --- a/Source/santasyncservice/SNTSyncState.h +++ b/Source/santasyncservice/SNTSyncState.h @@ -68,6 +68,7 @@ @property NSNumber *blockUSBMount; // Array of mount args for the forced remounting feature. @property NSArray *remountUSBMode; +@property NSString *overrideFileAccessAction; /// Clean sync flag, if True, all existing rules should be deleted before inserting any new rules. @property BOOL cleanSync; diff --git a/Source/santasyncservice/SNTSyncTest.m b/Source/santasyncservice/SNTSyncTest.m index 173e64ace..d8abd5b7b 100644 --- a/Source/santasyncservice/SNTSyncTest.m +++ b/Source/santasyncservice/SNTSyncTest.m @@ -12,6 +12,7 @@ /// See the License for the specific language governing permissions and /// limitations under the License. +#include #import #import @@ -281,6 +282,7 @@ - (void)testPreflightBasicResponse { XCTAssertEqual(self.syncState.eventBatchSize, 100); XCTAssertNil(self.syncState.allowlistRegex); XCTAssertNil(self.syncState.blocklistRegex); + XCTAssertNil(self.syncState.overrideFileAccessAction); } - (void)testPreflightTurnOnBlockUSBMount { @@ -318,6 +320,32 @@ - (void)testPreflightBlockUSBMountAbsent { XCTAssertNil(self.syncState.blockUSBMount); } +- (void)testPreflightOverrideFileAccessAction { + [self setupDefaultDaemonConnResponses]; + SNTSyncPreflight *sut = [[SNTSyncPreflight alloc] initWithState:self.syncState]; + + NSData *respData = [@"{\"override_file_access_action\": \"AuditOnly\", \"client_mode\": " + @"\"LOCKDOWN\", \"batch_size\": 100}" dataUsingEncoding:NSUTF8StringEncoding]; + + [self stubRequestBody:respData response:nil error:nil validateBlock:nil]; + + XCTAssertTrue([sut sync]); + XCTAssertEqualObjects(self.syncState.overrideFileAccessAction, @"AuditOnly"); +} + +- (void)testPreflightOverrideFileAccessActionAbsent { + [self setupDefaultDaemonConnResponses]; + SNTSyncPreflight *sut = [[SNTSyncPreflight alloc] initWithState:self.syncState]; + + NSData *respData = [@"{\"client_mode\": \"LOCKDOWN\", \"batch_size\": 100}" + dataUsingEncoding:NSUTF8StringEncoding]; + + [self stubRequestBody:respData response:nil error:nil validateBlock:nil]; + + XCTAssertTrue([sut sync]); + XCTAssertNil(self.syncState.overrideFileAccessAction); +} + - (void)testPreflightDatabaseCounts { SNTSyncPreflight *sut = [[SNTSyncPreflight alloc] initWithState:self.syncState]; @@ -603,6 +631,10 @@ - (void)testPostflightBasicResponse { self.syncState.blockUSBMount = @0; XCTAssertTrue([sut sync]); OCMVerify([self.daemonConnRop setBlockUSBMount:NO reply:OCMOCK_ANY]); + + self.syncState.overrideFileAccessAction = @"Disable"; + XCTAssertTrue([sut sync]); + OCMVerify([self.daemonConnRop setOverrideFileAccessAction:@"Disable" reply:OCMOCK_ANY]); } @end diff --git a/docs/development/sync-protocol.md b/docs/development/sync-protocol.md index 77d830ff5..ea105677f 100644 --- a/docs/development/sync-protocol.md +++ b/docs/development/sync-protocol.md @@ -135,11 +135,12 @@ The JSON object has the following keys: | batch_size | YES | integer | Number of events to upload at a time | 128 | | full_sync_interval | YES | integer | Number of seconds between full syncs | 600 | | client_mode | YES | string | Operating mode to set for the client | either "MONITOR" or "LOCKDOWN" | -| allowed_path_regex | NO | string | Regular expression to allow a binary to execute from a path | "/Users/markowsk/foo/.*" | +| allowed_path_regex | NO | string | Regular expression to allow a binary to execute from a path | "/Users/markowsk/foo/.\*" | | blocked_path_regex | NO | string | Regular expression to block a binary from executing by path | "/tmp/" | | block_usb_mount | NO | boolean | Block USB mass storage devices | true | | remount_usb_mode | NO | string | Force USB mass storage devices to be remounted with the following permissions (see [configuration](../deployment/configuration.md)) | | | clean_sync | YES | boolean | Whether or not the rules should be dropped and synced entirely from the server | true | +| override_file_access_action | NO | string | Override file access config policy action. Must be:
1.) "Disable" to not log or block any rule violations.
2.) "AuditOnly" to only log violations, not block anything.
3.) "" (empty string) or "None" to not override the config. | "Disable", or "AuditOnly", or "" (empty string) | #### Example Preflight Response Payload