diff --git a/Source/santad/EventProviders/SNTEndpointSecurityDeviceManager.mm b/Source/santad/EventProviders/SNTEndpointSecurityDeviceManager.mm index 3d0adc608..52a6c9168 100644 --- a/Source/santad/EventProviders/SNTEndpointSecurityDeviceManager.mm +++ b/Source/santad/EventProviders/SNTEndpointSecurityDeviceManager.mm @@ -211,6 +211,18 @@ - (instancetype)initWithESAPI:(std::shared_ptr)esApi return self; } +- (uint32_t)updatedMountFlags:(struct statfs*)sfs { + uint32_t mask = sfs->f_flags | mountArgsToMask(self.remountArgs); + + // NB: APFS mounts get MNT_JOURNALED implicitly set. However, mount_apfs + // does not support the `-j` option so this flag needs to be cleared. + if (strncmp(sfs->f_fstypename, "apfs", sizeof(sfs->f_fstypename)) == 0) { + mask &= ~MNT_JOURNALED; + } + + return mask; +} + - (BOOL)shouldOperateOnDisk:(DADiskRef)disk { NSDictionary *diskInfo = CFBridgingRelease(DADiskCopyDescription(disk)); @@ -327,7 +339,7 @@ - (void)performStartupTasks:(SNTDeviceManagerStartupPreferences)startupPrefs { if (startupPrefs == SNTDeviceManagerStartupPreferencesRemount || startupPrefs == SNTDeviceManagerStartupPreferencesForceRemount) { - uint32_t newMode = sfs->f_flags | mountArgsToMask(self.remountArgs); + uint32_t newMode = [self updatedMountFlags:sfs]; LOGI(@"Attempting to mount device again changing flags: 0x%08x --> 0x%08x", sfs->f_flags, newMode); @@ -411,11 +423,10 @@ - (es_auth_result_t)handleAuthMount:(const Message &)m { exit(EXIT_FAILURE); } - uint32_t mountMode = eventStatFS->f_flags; pid_t pid = audit_token_to_pid(m->process->audit_token); LOGD( @"SNTEndpointSecurityDeviceManager: mount syscall arriving from path: %s, pid: %d, fflags: %u", - m->process->executable->path.data, pid, mountMode); + m->process->executable->path.data, pid, eventStatFS->f_flags); DADiskRef disk = DADiskCreateFromBSDName(NULL, self.diskArbSession, eventStatFS->f_mntfromname); CFAutorelease(disk); @@ -432,18 +443,17 @@ - (es_auth_result_t)handleAuthMount:(const Message &)m { if (shouldRemount) { event.remountArgs = self.remountArgs; - uint32_t remountOpts = mountArgsToMask(self.remountArgs); - if ([self remountUSBModeContainsFlags:mountMode] && + if ([self remountUSBModeContainsFlags:eventStatFS->f_flags] && m->event_type != ES_EVENT_TYPE_AUTH_REMOUNT) { LOGD(@"Allowing mount as flags contain RemountUSBMode. '%s' -> '%s'", eventStatFS->f_mntfromname, eventStatFS->f_mntonname); return ES_AUTH_RESULT_ALLOW; } - uint32_t newMode = mountMode | remountOpts; + uint32_t newMode = [self updatedMountFlags:eventStatFS]; LOGI(@"SNTEndpointSecurityDeviceManager: remounting device '%s'->'%s', flags (%u) -> (%u)", - eventStatFS->f_mntfromname, eventStatFS->f_mntonname, mountMode, newMode); + eventStatFS->f_mntfromname, eventStatFS->f_mntonname, eventStatFS->f_flags, newMode); [self remount:disk mountMode:newMode semaphore:nil]; } diff --git a/Source/santad/EventProviders/SNTEndpointSecurityDeviceManagerTest.mm b/Source/santad/EventProviders/SNTEndpointSecurityDeviceManagerTest.mm index ed79552c1..fdad20a7b 100644 --- a/Source/santad/EventProviders/SNTEndpointSecurityDeviceManagerTest.mm +++ b/Source/santad/EventProviders/SNTEndpointSecurityDeviceManagerTest.mm @@ -55,6 +55,7 @@ - (instancetype)init; - (void)logDiskAppeared:(NSDictionary *)props; - (BOOL)shouldOperateOnDisk:(DADiskRef)disk; - (void)performStartupTasks:(SNTDeviceManagerStartupPreferences)startupPrefs; +- (uint32_t)updatedMountFlags:(struct statfs*)sfs; @end @interface SNTEndpointSecurityDeviceManagerTest : XCTestCase @@ -455,6 +456,23 @@ - (void)testPerformStartupTasks { } } +- (void)testUpdatedMountFlags { + struct statfs sfs; + + strlcpy(sfs.f_fstypename, "foo", sizeof(sfs.f_fstypename)); + sfs.f_flags = MNT_JOURNALED | MNT_NOSUID | MNT_NODEV; + + SNTEndpointSecurityDeviceManager *deviceManager = [[SNTEndpointSecurityDeviceManager alloc] init]; + deviceManager.remountArgs = @[ @"noexec", @"rdonly" ]; + + // For most filesystems, the flags are the union of what is in statfs and the remount args + XCTAssertEqual([deviceManager updatedMountFlags:&sfs], sfs.f_flags | MNT_RDONLY | MNT_NOEXEC); + + // For APFS, flags are still unioned, but MNT_JOUNRNALED is cleared + strlcpy(sfs.f_fstypename, "apfs", sizeof(sfs.f_fstypename)); + XCTAssertEqual([deviceManager updatedMountFlags:&sfs], (sfs.f_flags | MNT_RDONLY | MNT_NOEXEC) & ~MNT_JOURNALED); +} + - (void)testEnable { // Ensure the client subscribes to expected event types std::set expectedEventSubs{