Normal view

There are new articles available, click to refresh the page.
Before yesterdayMain stream

Launching apps in Sonoma 14.6.1: Conclusions

By: hoakley
3 September 2024 at 14:30

Over a series of three articles last week, I pored over thousands of log entries to examine how macOS Sonoma 14.6.1 checks applications it’s launching, under normal full security settings, with reduced security, and for known malware. This article draws together my conclusions from those tests run in virtual machines on an Apple silicon Mac.

Layered security

Like other security functions in macOS, app launch security is built in layers, including checks of

  • code-signing certificates (multiple times);
  • CDHashes, including their consistency, and against Apple’s database for notarized apps, and their revocation;
  • quarantine extended attributes, which normally trigger a user consent dialog, and may result in app translocation;
  • previous launch, in the LaunchServices database;
  • matches with Yara rules in XProtect’s data;
  • user consent to a first launch prompt dialog;
  • launch and other constraints.

Additional data may also be collected and stored in the provenance database that first appeared in Ventura.

Not all checks are performed on every launch of an app. At a minimum, for a notarized app that has been run only recently, these might consist of only local checks against CDHashes and with the app’s existing entry in the LaunchServices database. Checks are also modified by reducing security settings:

  • Disabling Gatekeeper checks doesn’t stop those checks from taking place, but apparently ignores some results, notably those obtained by XProtect. It doesn’t affect checks of CDHashes against Apple’s database.
  • Disabling SIP has more pervasive effects in largely disabling the com.apple.syspolicy sub-system, affecting several layers, although checks of CDHashes against Apple’s database are unaffected.

com.apple.syspolicy

In full security conditions, one sub-system dominates log entries concerning app launch security, com.apple.syspolicy. This is clearest in Gatekeeper and XProtect checks. Although the log entries that follow may appear bewildering, they are the best illustration of this point.

When launching a notarized app that hasn’t previously been run on that Mac and has a quarantine xattr, Gatekeeper and XProtect scans are reported in the following sequence of entries:
com.apple.syspolicy.exec GK process assessment: <private> <-- (<private>, <private>)
com.apple.syspolicy.exec Gatekeeper assessment rooted at: <private>
com.apple.syspolicy.exec Skipping TCC check due to process: 692, 0, 692
com.apple.syspolicy.exec queueing up scan for code: PST: (vuid: 7C5C43BF-A338-4228-B61E-5038F1D93EDB), (objid: 62947), (team: (null)), (id: (null)), (bundle_id: (null))
com.apple.syspolicy.exec starting work for scan for code: PST: (vuid: 7C5C43BF-A338-4228-B61E-5038F1D93EDB), (objid: 62947), (team: (null)), (id: (null)), (bundle_id: (null))
com.apple.syspolicy.exec allowUI is YES, creating codeEval object: PST: (vuid: 7C5C43BF-A338-4228-B61E-5038F1D93EDB), (objid: 62947), (team: (null)), (id: (null)), (bundle_id: (null))
com.apple.syspolicy.exec Adding default exception for team: <private>
com.apple.syspolicy.exec Registered app bundle for protection: PST: (vuid: 7C5C43BF-A338-4228-B61E-5038F1D93EDB), (objid: 62947), (team: QWY4LRW926), (id: (null)), (bundle_id: (null))
com.apple.syspolicy.exec GK performScan: PST: (vuid: 7C5C43BF-A338-4228-B61E-5038F1D93EDB), (objid: 62947), (team: QWY4LRW926), (id: (null)), (bundle_id: (null))
com.apple.xprotect XProtectScan beginAnalysisWithResultsHandler continueOnError is set to 0
com.apple.xprotect XPAssessment performAnalysisOnFileImpl continueOnError set to 0
com.apple.xprotect Xprotect is performing a direct malware and dylib scan: <private>

Those checks later complete in entries such as:
com.apple.syspolicy.exec GK Xprotect results: PST: (vuid: 7C5C43BF-A338-4228-B61E-5038F1D93EDB), (objid: 62947), (team: QWY4LRW926), (id: (null)), (bundle_id: (null)), XPScan: 0,-7676743164328624005,2024-08-26 08:19:01 +0000,(null)
com.apple.syspolicy.exec GK scan complete: PST: (vuid: 7C5C43BF-A338-4228-B61E-5038F1D93EDB), (objid: 62947), (team: QWY4LRW926), (id: (null)), (bundle_id: (null)), 4, 4, 0
com.apple.syspolicy.exec scan finished, waking up any waiters: PST: (vuid: 7C5C43BF-A338-4228-B61E-5038F1D93EDB), (objid: 62947), (team: QWY4LRW926), (id: co.eclecticlight.SystHist), (bundle_id: co.eclecticlight.SystHist)
com.apple.syspolicy.exec App gets first launch prompt because responsibility: <private>, <private>
com.apple.syspolicy.exec GK evaluateScanResult: 0, PST: (vuid: 7C5C43BF-A338-4228-B61E-5038F1D93EDB), (objid: 62947), (team: QWY4LRW926), (id: co.eclecticlight.SystHist), (bundle_id: co.eclecticlight.SystHist), 1, 0, 1, 0, 4, 4, 0
com.apple.syspolicy.exec GK eval - was allowed: 1, show prompt: 1
com.apple.syspolicy.exec Skipping TCC check due to process: 692, 0, 692
com.apple.syspolicy Found console users: <private>
com.apple.syspolicy.exec Prompt shown (5, 0), waiting for response: PST: (vuid: 7C5C43BF-A338-4228-B61E-5038F1D93EDB), (objid: 62947), (team: QWY4LRW926), (id: co.eclecticlight.SystHist), (bundle_id: co.eclecticlight.SystHist)

When SIP has been disabled, there are precious few entries from com.apple.syspolicy or com.apple.syspolicy.exec. Instead, XProtect appears to be left to its own devices, and doesn’t fare well:
com.apple.xprotect XPAssessment performAnalysisOnFileImpl continueOnError set to 0
com.apple.xprotect XprotectService Calling SecAssessmentCreate with URL <private>, context <private>
XprotectService SecTrustEvaluateIfNecessary
com.apple.xprotect XprotectService Bundle is not apple signed
com.apple.xprotect XprotectService Bundle size result: 18388222 (YES)
com.apple.xprotect XprotectService Always scan: YES
com.apple.xprotect XprotectService Starting malware scan for: <private>
kernel XprotectService [697] crossed memory high watermark (15 MB); EXC_RESOURCE
kernel Full corpse enqueued for XprotectService
com.apple.xnu memorystatus kernel kernel EXC_RESOURCE -> XprotectService[697] exceeded mem limit: ActiveSoft 15 MB (non-fatal)
ReportCrash event condition bump 0 -> 1
ReportCrash post-exception thread qos drop 21 -> 17
ReportCrash PID 697 exceeded the memory high watermark; Invoking ReportMemoryException with corpse.

There are no other entries referring to Gatekeeper or those checks. The effects of disabling SIP appear extensive and pervasive throughout several of the layers of app launch security.

CDHashes are central

With the adoption of notarization, apps run in macOS should now fall into one of five categories:

  • signed by Apple, either its own apps or those delivered through its App Store;
  • notarized by Apple, with its CDHashes added to Apple’s database;
  • signed (either with a Developer certificate, or ad hoc) locally, and not distributed over the internet, with its own unique CDHashes;
  • unwanted or malicious, with revoked CDHashes,
  • unrecognised, and potentially malicious.

These emphasise the importance of the online ‘notarization’ checks of CDHashes performed in all circumstances where macOS doesn’t have previous records of saved CDHashes for that code. Their primary purpose isn’t to validate notarization, but to identify code as known good, known bad, or unknown. When Apple’s security engineers identify new malware, its CDHashes can quickly be added to the database as being revoked, so ensuring that all subsequent checks of the same CDHash will be classified as revoked, for malicious code. This is a rapid response that should have no false positives, in which benign code is mistakenly identified as being malicious.

Typically, the checking sequence is reported in the log with:
com.apple.syspolicy looking up ticket: <private>, 2, 1
com.apple.syspolicy cloudkit record fetch: <private>, <private>
com.apple.syspolicy cloudkit request cache info: <private>, max-age=300
com.apple.syspolicy CKTicketStore network reachability: 1, Mon Aug 26 09:15:45 2024
com.apple.syspolicy Inserting ticket: <private>
com.apple.syspolicy completing lookup: <private>, 0

[and so on with further lookups]
and those are among the only entries from com.apple.syspolicy seen when SIP is disabled.

When full security is enabled, those are completed with
com.apple.syspolicy.exec GK evaluateScanResult: 0, PST: (vuid: 7C5C43BF-A338-4228-B61E-5038F1D93EDB), (objid: 62947), (team: QWY4LRW926), (id: co.eclecticlight.SystHist), (bundle_id: co.eclecticlight.SystHist), 1, 0, 1, 0, 4, 4, 0
But when SIP is disabled, those don’t appear, and seem to be substituted by application of Security rule 11 instead.

The downside of CDHash checks is that their false negative rate can be alarmingly high. Change a single bit in the code being hashed, and the hash will amplify that change, and is completely different. Hence the importance of notarization to establish which CDHashes definitely aren’t from malicious code.

One threat to this system occurs when a user mistakenly blocks their Mac from connecting to Apple’s database using CloudKit, for example using a misconfigured software firewall. Without a suitable vulnerability, malicious software shouldn’t be able to use this approach to block a payload from being checked.

I don’t know whether any third-party security products use a similar checking mechanism with their own local or remote CDHash databases, but this appears to be a great advantage to the protection built into macOS.

Performance

Two of the checks performed with full security enabled are dependent on the size of the app being checked. Fully validating an app’s CDHashes against those in its signature or notarization ticket should benefit from hardware acceleration, particularly on Apple silicon, and can be tackled hierarchically. It appears unlikely to result in significant delays to launching an app.

XProtect scans are more likely to be responsible for observable delays in app launch times, though. With the recent growth in the number of Yara rules, and their length, scans performed after an app’s first launch are the most probable cause of large and complex app bundles requiring several seconds before the app can be run.

Summary

I have updated the flow chart I first proposed as a result of observations made of app launches in Sonoma 14.4.1:

launchsonomaapp2

This is also available as a tear-out PDF here: launchsonomaapp2

I welcome any evidence that will refine and improve that, please.

Previous articles

Launching apps in Sonoma 14.6.1: Full security
Launching apps in Sonoma 14.6.1: Reduced security
Launching apps in Sonoma 14.6.1: Known malware
How does Sonoma check an app before launch? (Sonoma 14.4.1)

Gatekeeper and notarization in Sequoia

By: hoakley
10 August 2024 at 15:00

There has been a recent outcry over one quietly mentioned change coming in macOS Sequoia, making it harder to run apps that haven’t been notarized by Apple. As there’s some confusion as to exactly what’s going on, this article explains how this should work, and what benefits notarization brings in return for this added inconvenience.

How it used to work

Although Apple has required developers to notarize their macOS apps for several years, starting back in Mojave 10.14.5, it has so far done little to enforce this requirement, except in special cases such as kernel extensions. The first of my free apps to be notarized was LockRattler, back at the end of July 2018, over six years ago, when Apple referred to making notarization obligatory at some time in the future.

In Sonoma and earlier, any app that hasn’t been notarized, but has been quarantined because it has been downloaded from the internet (or a similar cause), won’t open first time from a normal double-click. Instead the user has to select the Open command from the Finder’s contextual menu, resulting in a dialog giving the user the choice of opening the app in spite of it not being notarized and ‘checked for malicious software by Apple’. Once that first run has been completed successfully, no further prompts result, and the app runs normally thereafter.

How Sequoia will work

Changes are only enforced on apps that have been quarantined because of the way they arrived on that Mac. If an app doesn’t have a quarantine extended attribute with the quarantine flag set, although notarization is still checked by Gatekeeper, the app is allowed to run without any additional action by the user. This also allows you to continue to build your own apps locally, sign them using ad hoc certificates, and run them as before. Where this could get more inconvenient is with modes of transfer such as AirDrop that do put apps into quarantine, although they may not have been outside your local network.

Gatekeeper will then refuse to run for the first time those apps that aren’t notarized, if they’re in quarantine. The only way that you’ll then be able to launch an unnotarized app is by adding it to a list of exemptions using Privacy & Security settings. That’s performed on an individual basis, per app, as Apple has now announced to developers.

None of this applies to apps supplied by Apple, or third-party apps supplied through the App Store, which are signed by Apple, not notarized, and aren’t quarantined.

There are two main ways to circumvent this process.

You could strip the quarantine extended attribute before trying to run the app for the first time. This is a potentially dangerous workaround, as it bypasses first run checks that could spot malware. For those of us who often transfer our own apps for testing using AirDrop, it’s easy to drop them into a folder, Zip that, then on the recipient Mac strip the quarantine xattr before unZipping the archive. My utility Cormorant can make that even simpler. If you were to opt to do that, you must be absolutely certain of the provenance of the app you’re transferring.

For those who have test systems that frequently need to run unnotarized apps, another potential solution is to disable Gatekeeper on them. Perhaps anticipating a move to do that, Apple has changed how this can be done, making it a two-step procedure, in which you first allow the disabling of checks, then in Privacy & Security settings control how that is implemented. Apple encourages those who need to do this to use installed profiles instead, or handle it through MDM payloads. This has been explored in detail by Brandon Dalton in his account of these changes.

I’m frequently surprised to learn how many Mac users have disabled Gatekeeper checks in the past and forgotten to reinstate them, only to be reminded when they later run SilentKnight for the first time.

There’s also a third method that’s little-known, although in the early years of notarization it was practised widely, and that’s notarizing other developers’ apps. Apple has made it clear that submission of an app for notarization doesn’t have to be performed by its developer, the owner of the certificate used to sign the app with, but anyone with a current developer account with Apple can do so provided they follow the correct process. This is most appropriate for those in enterprise and organisations who need to use third-party products that aren’t yet notarized by their developer.

Why notarization?

Superficially, notarization brings two obvious benefits, in apps being checked for malware by Apple before they’re issued a notarization ticket, and in the ‘hardened’ runtime they’re required to adopt to qualify for notarization. Those remain controversial; in the past some malware was apparently notarized, although that seems to have resulted in more stringent checks being applied. But those overlook its greatest benefit.

Code-signing used to be considered an effective way of ensuring the integrity and provenance of executable code, but has now become too low a bar to be effective. It’s all too easy to strip a signature and resign code, and in any case acquiring developer certificates is neither expensive nor difficult. Although Apple does revoke certificates promptly once their abuse is detected, the interval between first abuse and revocation is often sufficient for most who develop malware. Once one certificate has been revoked, it’s then easy to move on and use another, always keeping one step ahead of Apple.

In recent versions of macOS, executable code is recognised and managed using its cdhashes, a tree of hashes of its components within a bundle, for instance. A notarization ticket contains cdhashes that have been accepted by Apple as a record of that app when it underwent notarization. To verify the integrity and authenticity of any notarized code, all macOS has to do is compare freshly computed cdhashes against those provided in the app and its ticket, and against those in Apple’s notarization records. This presents a much higher bar to those trying to masquerade as or tamper with notarized executable code.

By making it harder for a user to run unnotarized code, the chances of that user inadvertently running malicious code are considerably reduced.

Further reading

Notarization for developers (Apple)
How does Sonoma check an app before launch?

❌
❌