The Rules for Full Disk Access

Because we are still anxiously awaiting the documentation on the workings of the whitelist in System Preferences > Security and Privacy > Full Disk Access (previously Application Data in earlier betas), I report the following experimental results with macOS 10.14 Beta 7 (18A365a): [Edit 2018-08-22: Beta 8 seems to be the same.]


  • If I click the + button under the whitelist and enter my .app, it gets access as expected, but only if it is located in /Applications, and not attached to by lldb (not running in Xcode).
  • Even if the full path to a command-line Helper tool which my app contains (/Applications/MyApp.app/Contents/Helpers/MyHelper) is explicitly entered into the Full Disk Access list (*), and it appears in the whitelist separately from my .app, this command-line tool will be denied access when it runs. (Access worked in macOS 10.14 Beta 3. Beta 4 broke it.)
  • After I similarly enter /Applications/Arq.app/Contents/Library/Arq Agent.app into the whitelist, overnight backups in the background by the backup app which I use, Arq, start working again.
  • If I have one copy of a .app already entered into the whitelist, and + add another copy, the whitelist silently remains the same, showing only one entry for the duplicated app. (Unfortunately, the whitelist does not show an item's path in any way – no tooltip.)


Therefore, I conclude that, in order for a executable to be granted Full Disk Access, it must be…


  • the main executable of a whitelisted .app, although it is OK for this whitelisted app to be a helper/child of another app, located in the parent app's Contents/Library.
  • not attached to by a debugger.
  • located within /Applications.


Although whitelisting a certain .app will enable its main executable and any child processes, it will not enable a helper/child app when the helper/child is launched by others in the background. The helper/child must itself be explicitly present in the whitelist.


* * *


If anyone can confirm, deny, or elaborate on these conclusions, I would really appreciate it. There is maybe only four weeks to go, and it appears that I have a lot of work to do. Was the breaking of command line tools in Beta 4 intentional?


(*) To enter a helper component such as this into the whitelist, because the navigation sheet presented by the + button will not navigate into .app packages, the user must hit the + button, then ⌘⇧G, then enter the absolute path to the helper.


P.S. to other developers: The new restrictions are apparently implemented with System Integrity Protection (SIP). You can still debug your app if you disable SIP 😟

Replies

In my experience, I have found that helper tools need to be app bundles in order to inherit any privileges granted by the "Full Disk Access" category. In my case, I had 2 different helper tools. One was embedded in my app, and the other was external. In my initial testing, I found that the embedded helper tool inherited the "Full Disk Access" privilege when I added my app to that category. However, when I added the external helper tool to the category, it did not get full access. This puzzled me for quite a while, as to why the embedded tool worked but the external one didn't. Then it dawned on me that the embedded one was an app bundle and the external one was a command-line tool. So I converted my external tool to be an app bundle, added it to the "Full Disk Access" category, and found that it now, indeed, had full access, just like the embedded tool.

@fschilling, in your story, I read that

  • embedded = app bundle = works
  • external = command-line tool = does not work

and, furthermore, your embedded helper worked if you added it to Full Disk Access as a separate entry.


My conclusion: Your observations corroborate some of mine. Thank you!

With regards helper tools, does your tool:

  • Have a bundle ID, set via the

    __info_plist
    section in the executable?

    To get this, set both the “Info.plist File” (

    INFOPLIST_FILE
    ) and the “Create Info.plist Section in Binary” (
    CREATE_INFOPLIST_SECTION_IN_BINARY
    ) build settings.
  • Have that bundle ID as a ‘child’ of the app’s bundle ID?

    For example, your app might be

    com.example.foo
    and your bundle ID might be
    com.example.foo.helper
    .
  • Have a code signing identifier that matches its bundle ID?

    You can dump the code signing identifier using

    codesign -d -vvv /path/to/your/tool
    . For example:
    $ codesign -d -v /Library/PrivilegedHelperTools/com.anarchistturtle.QCDImagerHelper 2>&1 | grep Identifier
    Identifier=com.anarchistturtle.QCDImagerHelper
    …

    .

I haven’t yet researched all of the details of this issue but it’s clearly all about code identity, and messing up one or more of the above is a common cause of code being misidentified.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

One clarification. I did not have to add the embedded helper, separately, in order for it to work. All I had to do was add the main app (i.e. the app that the embedded helper was within) to the category. Once the main app was added to "Full Disk Access", all of its embedded helper apps were automatically granted full access too.

Thank you, Quinn. My build now meets the three requirements you stated. To verify:


ACA80003 jk$ otool -s __TEXT __info_plist "/Applications/BookMacster.app/Contents/Helpers/Sheep-Sys-Worker" | xxd -r 
...
    CFBundleIdentifier
    com.sheepsystems.BookMacster.Worker
...
ACA80003 jk$ cat "/Applications/BookMacster.app/Contents/Info.plist"
...
    CFBundleIdentifier
    com.sheepsystems.BookMacster
...
ACA80003 jk$ codesign -d -vvv /Applications/BookMacster.app/Contents/Helpers/Sheep-Sys-Worker
Executable=/Applications/BookMacster.app/Contents/Helpers/Sheep-Sys-Worker
Identifier=com.sheepsystems.BookMacster.Worker
...


As you can see, (1) the bundle identifier com.sheepsystems.BookMacster.Worker is stated in the embedded Info.plist of the helper tool Sheep-Sys-Worker, (2) it is a child of the main app's bundle identifier com.sheepsystems.BookMacster, and (3) it matches the tool's code signing identifier.


The result is that access to Mojave-protected files is still apparently denied by System Integrity Protection. I found this in the Console after testing:


... Sheep-Sys-Worker  open on /Users/jk/Library/Safari/Bookmarks.plist: Operation not permitted


It did work until Beta 4, although I had to explicity add the helper to the Application Data Full Disk Access whitelist. I explained this in Bug 42602218 on July 25, and this bug has recently been marked Closed Duplicate 41034701. What I have been trying to determine is: Does Closed mean we're going to fix it before the GM, or does it mean the security team has decided that denying access to command-line helpers is intended behavior. Because we're up to Beta 8 now and it's still broken, I suspect the latter, but if you could verify that I'd really appreciate it.


By the way, I'm surprised that code signing is involved here, because my main app, when added to the whitelist, gets access to Mojave-protected files even if it is not code signed at all.

Thank you for the clarification, fschilling. First of all, let me clarify for other readers that your embedded helper is in fact an app bundle and not a command-line tool, and we all agree that app bundles work.


I am a user of the backup app Arq. I manually command Arq to perform a backup each night before leaving the computer. Back in July, I found that Arq reported errors accessing Mojave-protected files unless I explicitly and separately added its helper Arq Agent to the Application Data Full Disk Access whitelist. Although there was one glitch a couple weeks ago when I had to re-add it, everything worked until this morning, when my Arq report for last night indicated that it again could not access Mojave-protected files. So I did this:


  • Changed a bookmark in Safari (to ensure that Arq would again need to access a Mojave-protected file)
  • Removed both Arq and Arq Agent from the Full Disk Access whitelist
  • Following your suggestion, I added back only the main app, Arq.
  • Commanded Arq to perform a backup.


To my delight, it worked. So I agree with you that, now, in Mojave Beta 8, whitlelisting a main app will enable its enclosed helper, if the helper is itself packaged as an application. That is really good news, because digging into the package and adding the helper would have scared away most users. Another improvement I've seen recently is that users can drag and drop apps into the whitelist.


I am still concerned, though, that there have been two occasions in the last month when I've needed to re-add Arq to the whitelist. This morning's failure may have been caused by me poking around yesterday in the whitelist, removing and adding my own app and its helper. But I did not touch the entries Arq or Arq Helper. They were still in the list this morning. I also wonder if users are going to need to re-add our apps to the whitelist each time our apps are updated. I hope that y'all keep up the testing, discussion, and bug reporting.

Is there an API to determine whether I've got full disk access already? I'd really like to make Arq prompt the user only if he/she hasn't already given the permission.

After installing Mojave Beta 9 this morning, things make a little more sense.


The whitelist in System Preferences > Security & Privacy > Full Disk Access now has a contextual menu with one item: Show in Finder. But now, it does not matter that much because it apparently works by code identity as Quinn suspected. That is, I can drag the app from the Xcode Build folder into the whitelist, copy the app to /Applications, run from there, or vice versa, and it still gets access to Mojave-protected files even though Show in Finder in the whitelist is not the copy which is running.


I still see no requirement for code signing, though. Apps get access to Mojave-protected files whether code signed or not. And there is still no access when debugging (debugger attached). That I recall being stated in the WWDC 2018 session.


Regarding my original concern, a helper tool installed via the Service Management API gets access to Mojave-protected files if its parent main app is in the whitelist, and even after the parent is quit, but only when it is launched by Service Management. If you launch the helper's executable from the command line, it is denied access. So I presume that a bundle-less command-line helper in Contents/Helpers, as discussed in my original post, would likewise be denied.


I can live with this, and it makes sense. I just wish it was documented somewhere, so I don't spend the next few weeks re-architecting my intermittently-running command-line tool into a constantly-running service under the Service Management API, only to have the rug pulled out in the Mojave GM.

I don't think we are going to get such an API, at least not in Mojave 10.14.0. You could do what I do in my demo app, which is to try to access a Mojave-protected file. Sorry, wrote in Objective-C because I was in a hurry 🙂


NSError* error = nil;
    NSData* data = nil;
    NSString* path = [NSHomeDirectory() stringByAppendingPathComponent:@"Library/Safari/Bookmarks.plist"];
    if (path) {
        data = [NSData dataWithContentsOfFile:path];
        if (!data) {
            if ([[NSFileManager defaultManager] fileExistsAtPath:path]) {
                error = [NSError errorWithDomain:@"MojaveAccessErrorDomain"
                                            code:666
                                        userInfo:@{
                                                   NSLocalizedDescriptionKey : @"Looks like we've been denied."
                                                   }];
            }
        }
    }
}


Then return YES if nil error. But pick a better file to test for your application, because, last time I checked, Safari's Bookmarks.plist does not exist in a virgin macOS user account until after the user adds one of their own bookmarks, and most users under the age of 50 nowadays have no idea what a bookmark is 🙂

Yes, that's certainly the fallback plan but it would be nice to have a proper API.

The ideal thing would be an API call that causes a prompt to the logged-in user to grant the app Full Disk access because there's no way to trigger a prompt like that right now, and that's what backup apps need.

The ideal thing would be an API call …

Please do file an enhancement request that describes your requirements and explains the less-than-ideal workaround you’re using in the absence of the idea solution.

I’d also appreciate you posting your bug number here, just for the record.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Enhancement requests have probably already been filed, by the participants in this thread. The post by me on August 31 contains text for such an enhancement request, which all are welcome to plagiarize.


My Bug Number is 43961364.

“Sarah.Moreno.1994”

Hi,

We have a similar situation with some helper tools being located outside our main App, but we did not succeed in making your solution work: Our helper tools get EPERM erors when attempting to access the files in the protected user folders.

The main difference to your example is that our helper tools are located inside a bundle like this:


/Library/MyCompany/MyBundle.bundle/Contents/MacOS/helpertool1
/Library/MyCompany/MyBundle.bundle/Contents/MacOS/helpertool2


The App identifier is in the form:

com.myCompany.myProduct.application


For the tools we have:

com.myCompany.myProduct.application.component1.tool1
com.myCompany.myProduct.application.component1.tool2


We have also tried to pack our tools inside a bundle located in

/Library/PrivilegedHelperTools

but with no success.


Note that communication with the tools is performed via XPC and that the identifiers used for communication which are advertized via plist files in /Library/LaunchDaemons/ are different.


Any idea about what could fail or what we could have missed ?

Thank you in advance,

Marc

My understanding is that the following two scenarios are expected to work:

  • Bundle your helper inside your app. In this case the helper will automatically be whitelisted because the parent app was whitelisted.

    The scenario is most commonly used for non-privileged things, like login items installed via

    SMLoginItemSetEnabled
    .
  • Explicitly ‘bless’ your helper. If your helper does not live within your app, the user will have to explicitly grant it full disk access in System Preferences.

    The scenario is most commonly used for privileged helper tools.

It sounds like you’re shooting for the second option. Did you explicitly grant full disk access to your tools?

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"