Mojave’s privacy protection is complex and will crash innocent apps

With Mojave’s release possibly only a couple of weeks away, I’ve been trying to resolve problems in my own apps which seriously limit their functionality when they’re run in macOS 10.14. What I’ve learned is how complex its new privacy protection is, and how users, sysadmins and developers may be in for a shock when they upgrade to Mojave.

Many apps won’t work like they used to, even when their developers think that they’ve catered for Mojave’s new privacy rules. And in many cases, that means that perfectly innocent apps will crash when they shouldn’t.

I have, for example, built a new release of my extended attribute editor xattred, which is properly set up to work in Mojave’s new Dark Mode. Yet every time you try to use it to examine protected files in your Calendar, xattred crashes. This is in spite of it being given “Full Disk Access” in the Privacy tab of the Security & Privacy pane.

According to Kelly Yancy in his segment of session 702 at WWDC 2018:
The “user can pre-approve such apps by adding them to the new System Application Data category in the System Preferences Security and Privacy pane. By doing so, the user preauthorizes those apps to access all of their privacy-sensitive data without prompting.”
(The System Application Data item has since been renamed Full Disk Access)

moprivprobs01

I thought at first that this might be a bug or incomplete feature, but it has persisted through all recent beta releases of Mojave, up to and including that current. [This does turn out to be a bug: see the Postscript below.] The problem is that there is nothing that the user can do to change this behaviour, as users can’t add apps to the Calendar, Contacts, and most other items in Privacy settings: that can only be arranged via macOS.

This is because the way that you add an app to the Calendar list is to use that app to try to access one of those protected items.

moprivprobs02

Up pops a dialog, inviting the user to agree to the app having that access. If the user clicks on OK, then that app is added to the list of apps which is entitled to access those protected items, and appears in Privacy settings, where the user retains control using a checkbox.

moprivprobs03

Two important lessons here are:

  • Adding an app to the Full Disk Access list doesn’t actually give it full disk access [it should do, though: see Postscript below].
  • The only way to give an app access to some protected data is to try accessing that data using that app.

But in the case of xattred, instead of the app invoking the user consent dialog, all it did was crash, which prevents the user from doing anything about the problem.

I then tested an older version of xattred, and discovered that, instead of crashing, it did produce the expected user consent. Once added to that list, the newer version stopped crashing, and could access all protected Calendar files without any more dialogs.

What was even more confusing here was that, when xattred crashed, it wasn’t even running its ‘own’ code: the crashes occurred when selecting a protected file in the Open File dialog, rather than after clicking on the Open button. I therefore resorted to inspecting the log, to discover what I was doing wrong.

Reproducing the crash in xattred and browsing the unified log revealed that the com.apple.TCC subsystem, which includes the all-important service tccd, was checking for two key items: a usage string, and the version of the SDK used to build the app:
30.582433 Info com.apple.TCC -[TCCDAccessIdentity _initFromProcessStateAndBinaryPathURL:dynamicCodeRef:preferMostSpecificIdentifier:]: bundle_url = file:///Applications/xattred.app/ for path file:///Applications/xattred.app/Contents/MacOS/xattred
30.582581 Info com.apple.TCC No usage string found (key:NSRemindersUsageDescription) for client[922] in bundle:<private>
30.582616 Info com.apple.TCC /Applications/xattred.app/Contents/MacOS/xattred (offset 0) linked against SDK version 0xa0e00
30.582638 Error com.apple.TCC Refusing TCCAccessRequest for service kTCCServiceReminders and client /Applications/xattred.app[922] without NSRemindersUsageDescription key
30.582835 Info com.apple.TCC Handling access request to kTCCServiceReminders, from co.eclecticlight.xattred, default_allow: 0, allowed: 0, prompt_count:0, update_access: 0, preflight: no
30.582861 Info com.apple.TCC Received asynchronous reply <dictionary: 0x600000ba5d40> { count = 2, transaction: 0, voucher = 0x600001d25270, contents =
"problem_key" => <string: 0x600003186b50> { length = 27, contents = "NSRemindersUsageDescription" }
"abort" => <string: 0x600003186a60> { length = 244, contents = "This app has crashed because it attempted to access privacy-sensitive data without a usage description. The app's Info.plist must contain an NSRemindersUsageDescription key with a string value explaining to the user how the app uses this data." }
}
30.582865 Error com.apple.TCC This app has crashed because it attempted to access privacy-sensitive data without a usage description. The app's Info.plist must contain an NSRemindersUsageDescription key with a string value explaining to the user how the app uses this data.

moprivprobs04

The reason that my recent version of xattred was crashing rather than invoking the user consent dialog was that it had been built using Xcode 10, so that I could port it to Swift 4.2 and make it fully compatible with Mojave and its Dark Mode. TCC then required it to have, in its Info.plist, a string for the NSRemindersUsageDescription key, which is not required if it is built using Xcode 9.

This was referred to somewhat ambiguously later in the same WWDC session:
“So these keys will be required for apps linked against the 10.14 SDK. So besides informing the user, these keys are also being used to inform the operating system that — as the developer — you intend for your app to access the user’s personal data. And should an app try to access the user personal data but not include the appropriate key and purpose string for that data, macOS Mojave assumes that that access was unintended — and the app exits.
For compatibility, these keys are optional for apps that link – that target older SDKs. So for example, if you have an app that still targets the 10.13 SDK and tries to access the user’s personal data via one of these APIs, the app will not exit but will display a prompt lacking the purpose string — like the first one that we saw a minute ago. So we still encourage you to include the Info.plist keys in your apps, even if you are targeting an older SDK, so that the user is better informed why your app is accessing their data.”

My app, xattred, is not Mojave-only, but “targets” macOS 10.11. However, because that version was built using Xcode 10, TCC requires it to have that usage description built into its Info.plist file. This doesn’t appear to have been given the publicity which it deserves.

Unfortunately, this problem gets worse.

I have many other apps which I don’t envisage users wanting to use to access protected items. Even with the knowledge that – when built using Xcode 10 – usage descriptions are required to prevent the app from crashing in this way, best practice is not to gratuitously provide it with a usage description on the off-chance that someone might need it. Otherwise, every app capable of opening a protected item would be given all the usage descriptions by default, which would defeat the whole purpose of these controls.

So, let’s say that a user decides that they want to access a protected file, perhaps an image in a Photos library, or one in Contacts, using an app which has been built using Xcode 10 so that it works nicely in Dark Mode, but that app doesn’t have strings in its Info.plist for NSPhotoLibraryUsageDescription or NSContactsUsageDescription.

What the user experiences is the app crashing, without being given any reason for that crash. Because it is an app crash, they complain to the developer, not to Apple. Even if they are savvy enough to recognise this might be a privacy protection issue, if they use their only control and add the app to the Full Disk Access list, it doesn’t stop the crashes [it should do: see Postscript].

Users cannot add their own items to customise an app’s Info.plist, as that breaks its code-signing, and Gatekeeper won’t let them run that app ever again. The only resolution to this problem is for the developer to make a new version of their app with that usage description added to the Info.plist file, and provide the user with that.

The lessons here are:

  • Making an app ‘more compatible’ with Mojave by building it using Xcode 10 may make it less compatible with Mojave, unless you add all the new usage strings.
  • The user doesn’t control access to their own private data. macOS does.
  • One simple solution for developers is to add all the usage strings to their apps’ Info.plist files, but that defeats the whole purpose.
  • Third-party developers are going to see a rise in support issues with Mojave because of these complex problems in its privacy protection.
  • Overall, users are likely to encounter more app crashes in Mojave than ever before in macOS.
  • Users are likely to find older apps crash less in Mojave than those built to be compatible with it.
  • None of this is going to be fun for system administrators.

Developers may also struggle to find support in Xcode 10 for these vital new additions to Info.plist. Clearly, no one told Xcode’s engineers about these changes either, as you won’t find these new usage descriptions easily.

moprivprobs05

I added mine to the Custom macOS Application Target Properties list, in the Info tab. Select an existing key and click on the + button to add a new property. Then type Privacy to display those concerning Mojave’s privacy features. The keys you should consider including are:

  • NSCalendarsUsageDescription – enables addition to the Calendars item in Privacy settings;
  • NSContactsUsageDescription – enables addition to the Contacts item in Privacy settings;
  • NSPhotoLibraryUsageDescription – enables addition to the Photos item in Privacy settings;
  • NSRemindersUsageDescription – enables addition to the Reminders item in Privacy settings;
  • NSSystemAdministrationUsageDescription – it’s not clear what this controls, but it isn’t scripting, for which see this article for the use of the NSAppleEventsUsageDescription property.

Note that TCC doesn’t appear to check whether the string supplied is informative or meaningful. I suspect that empty strings are not acceptable, but supplying the word “Because” should satisfy Mojave even though the user may be puzzled.

We now face a major task informing users that, when they upgrade to Mojave, these changes will affect them the moment that they try to access any of the protected items.

It’s worth pausing for a moment to consider whether Mojave’s current implementation of privacy protection is actually in the users’ interests. I know of no other situation in which an operating system deliberately crashes an app because it lacks an explanatory string like this. Unix and almost all other operating systems handle many requests to access the inaccessible, and respond by returning an error, which the calling app can trap for and handle gracefully, ensuring that the user is made fully aware of what went wrong.

Crashing an app while writing the only informative message in the unified log, alongside the log’s usual torrent of incomprehensible chatter, is less than helpful. Apple’s only log browser, Console, is still unable to provide ready access to that log message in retrospect (you’d have to make a logarchive and browse that instead).

Crashing an app in this way punishes the user most of all, who is likely to be the most puzzled as to why it has happened, and is the least able to do anything about it.

Crashing an app points the finger of blame at the app developer, who may never have envisaged that a user might try to open protected items using that app. The developer is then going to have to provide a lot of users with support over macOS features and foibles.

Although I haven’t looked at this in detail yet, Apple’s own apps, tools such as Preview, don’t seem to be subject to the same privacy rules. As far as I can tell at present, Preview doesn’t have any of the new usage descriptions in its Info.plist, doesn’t get listed in any of the items in the Privacy controls, but can open images in Photos libraries and Contacts, for example. So Apple has and uses for itself something which makes life easier for the user, but forces third parties through a complex and flawed system instead.

All this could be simpler if the user was able to add apps of their own choosing to all the lists in the Privacy settings, which is surely only correct if the user is to remain in control. And finally, as always, all this would be far, far simpler if Apple didn’t expect us to waste many hours trying to discover what it should be documenting for us as it is implemented.

I look forward to seeing Apple’s detailed and explicit user documentation in the next few weeks, when Mojave is released. I hope this article has helped you be better prepared, particularly if you are a developer yourself. But I haven’t finished yet: tomorrow I will tackle the even murkier topic of command tools and Mojave’s privacy protection.

Postscript:

Many thanks to @hey_pom, who very kindly got back to me saying that some of the behaviour I have observed is a bug. When a user adds an app to the Full Disk Access item in Privacy settings, that should grant full access and not barf in this way with Contacts information, etc. That is very good to know, and I have now reported this as a bug.

This should mitigate some of these issues. However, I stand by my other comments above. I still think that forced app crashes are a really bad idea, and that there are going to be significant support issues with Mojave’s release. Time will tell.

I have now been thinking about how developers can better inform users, and will be covering that in the near future, together with a notarized release of xattred which shouldn’t experience any problems in any release of Mojave.

Further update as of 5 September 2018:

The bug detailed above has now been fixed: congratulations and thank you to the Apple engineers who did that. Although Mojave’s privacy protection still needs care on the part of the developer and the user, this is a major step forward. I’m very much happier with it now.