In yesterday’s article, I showed how opening an app invariably results in signature checks on that app, but that in many cases errors returned for those checks don’t result in the app being stopped or terminated, or the user informed of the error. Today I will go a bit further and consider signature checking in different circumstances, to try to understand how this behaviour occurs.
My starting point is a comparison between the checks which take place when the app still bears a quarantine flag, and those run on a signed app which has been run from that path on previous occasions without problems.
The sequence of signature checks run on a quarantined notarized app is long and complex. It starts with checks by syspolicyd and lsd, the latter instigating translocation of the app. After those comes amfid, and the app is passed to XprotectService for checks for malware signatures and the like. Typically, for a small app, these take 0.6 seconds or more, and are considerably more thorough than any of the other checks seen.
In contrast, a signed or notarized app which is opened for the second or subsequent time from the same path is only normally checked by lsd and launchservicesd, which takes less than 0.03 seconds.
Signing errors are not only detected by the full checks performed when the quarantine flag is set, but also when an app is being run for the first time from a particular path. The latter doesn’t have the same effect as the quarantine flag, though: syspolicyd checks first and notes the discrepancy in the path from which the app is being opened. This is followed by lsd, and quite a thorough check by amfid which can take 0.15 seconds or more.
launchservicesd and lsd provide various services for Launch Services and CoreServices frameworks, and are not normally associated with security functions. Other signature checks are called by tccd, the TCC services daemon which is centred on privacy protection rather than security. So errors encountered in signature checks called by them are unlikely to escalate into intervention with that app.
The two security-oriented services which are more likely to act on signature errors are syspolicyd and amfid. syspolicyd is described in its man page as:
“syspolicyd embodies the system policy controlling what may be installed, loaded, executed, or otherwise used on the system. It manages the policy database file, and serves as a general oracle that other system components may use to determine the system policy’s verdict on a proposed operation.”
amfid is more obscure, the Apple Mobile File Integrity daemon, which checks the integrity of files in macOS (and in iOS). It plays a crucial role in detecting and acting on signature errors, as seen in the following log extract from an attempt to open an app with a discrepancy between its Info.plist and its signature:
00.444085 amfid Security SecTrustEvaluateIfNecessary
00.445546 com.apple.securityd rvc trustd trustd asynchronously fetching CRL (http://crl.apple.com/root.crl) for client (amfid/0#-1 LF=0)
00.445639 com.apple.securityd policy trustd trustd cert: AnchorTrusted =(leaf)[force]> 0
00.446897 com.apple.securityd security_exception amfid Security MacOS error: -67030
00.447297 syspolicyd Security SecTrustEvaluateIfNecessary
00.460716 syspolicyd syspolicyd Newer ticket (1545471544) present in db, ignoring ticket (1545471544)
00.460851 com.apple.securityd security_exception amfid Security MacOS error: -67030
00.460909 com.apple.securityd security_exception amfid Security MacOS error: -67030
00.460987 com.apple.securityd security_exception amfid Security MacOS error: -67030
00.461030 com.apple.securityd security_exception amfid Security MacOS error: -67030
00.461066 com.apple.MobileFileIntegrity amfid amfid amfid Basic requirement validation failed, error: (null)
00.461145 amfid amfid /Users/hoakley/Documents/test2/SignetTest5.app/Contents/MacOS/Signet signature not valid: -67030
00.461160 kernel AppleMobileFileIntegrity AMFI: code signature validation failed.
00.462137 amfid Security SecTrustEvaluateIfNecessary
00.463175 amfid Security SecTrustEvaluateIfNecessary
00.464527 com.apple.securityd rvc trustd trustd asynchronously fetching CRL (http://crl.apple.com/root.crl) for client (amfid/0#-1 LF=0)
00.464572 com.apple.securityd policy trustd trustd cert: AnchorTrusted =(leaf)[force]> 0
00.465748 com.apple.securityd security_exception amfid Security MacOS error: -67030
00.466118 com.apple.MobileFileIntegrity amfid amfid amfid <private>: Broken signature with Team ID fatal.
00.466220 kernel kernel proc 25832: load code signature error 4 for file "Signet"
00.473246 ReportCrash Symbolication *** task_malloc_get_all_zones: couldn't find libsystem_malloc dylib in target task
00.473321 ReportCrash ReportCrash Trying to extract VM information using cr2
In this, the first Trust Evaluation is called not by syspolicyd but by amfid. However, the response to the call by syspolicyd results in the entry in the security database (for another path to this app) being ignored, and the assessment being run afresh. com.apple.MobileFileIntegrity recognises the validation failure; after a second attempt to validate fails, the app is then crashed.
Had the app been opened from its previous known path, syspolicyd would have accepted its existing entry in the security database, and amfid wouldn’t have proceeded with action on the signature validation failure. Indeed, amfid wouldn’t have called for a Trust Evaluation before the app was opened successfully.
This shows how:
- A quarantine flag results in a full Gatekeeper check, which includes app translocation, in-depth evaluation of the signature, integrity checks by amfid, and XProtect check for malware, etc.
- Opening an app from a previously unknown path results in its existing entry in the security database being ignored, and additional checks of integrity by amfid. The app is not translocated, the signature is not evaluated as deeply (although more deeply than when opened from a known path), and it isn’t scanned by XProtect. This is, therefore, not a full Gatekeeper check, but an AMFI check for integrity.
- Opening an app from a known path results in signature checks for Launch Services and various CoreServices functions, not for security. Signature errors detected during that are likely (perhaps certain) to result in no further action.
- These processes are broadly similar in signed and notarized apps. I have not looked at them in detail in sandboxed apps, where signature checks are also required to check provisioning profiles for taskgated, the task_for_pid access control daemon.
- Signature checks are also performed extensively by TCC, in relation to its controls over access to protected data and services. This is a substantial topic in itself.
I wish you a very Happy Christmas, now that I have perhaps made better sense of what is going on when an app opens in macOS 10.14.2.