PrivilegedHelper has no access to Downloads folder unless the user manually enables Full Disk Access

Hi,

I realize that there was a similar question asked about a year ago, but I wasn't sure if it was appropriate to "piggy back" onto that thread, and it didn't seem to have a definitive solution. The thread I'm referring to is: https://developer.apple.com/forums/thread/131568?answerId=415860022

My problem is similar but perhaps not quite the same as I just have one app that 'owns' the helper tool.

I am currently on xcode 13 and Monterey. I implemented an app and privileged helper according to the EvenBetterAuthorizationSample, using SMJobBless and everything.

The Privileged helper is a console tool, with the sole purpose of running the installer command to install a downloaded installer package. The app and tool are codesigned, and the app has 'Privacy - Downloads Folder Usage Description' in the plist.

When I launch the app it should install a specified package via the helper tool.

And... it works great, which I was pleasantly surprised with given the complexity of this thing. There is just one problem:

The helper tool cannot access the Downloads folder. If the package is located in /users/me, no problem, but if it's /users/me/Downloads then installer can't access the file. This is not unique to '/usr/sbin/installer' command- I tested other commands like '/bin/ls'

If I look in Security & Privacy --> Privacy --> Full Disk Access, I can see the helper listed there as com.myCompany.myApp.helper but it is not checked. If I check it manually, then.. it works - Great! Only problem is, for this to work for a user it would have to fail once, and then I would have to explain to the user how to fix it and try again, which is very awkward.

While I'm doing testing, between tests I'm using launchctl to unload the helper, and removing it from LaunchDaemons and PrivilegedHelperTools. I'm also using 'tccutil reset SystemPolicyAllFiles com.myCompany.myApp'

Another observation: The app itself can somehow write files to the Downloads folder. And it doesn't show a dialog to ask for permission when I launch the app.

Obviously one solution is to not even use the Downloads folder these downloads. I could create a folder like /users/me/myDownloads, and download the packages there. That seems a bit silly... or maybe not?

Thanks for any help with this.

Obviously one solution is to not even use the Downloads folder these downloads.

That’s what I’d do. The Downloads folder is intended for user-visible downloads, but this download is something being done by your app for the benefit of your installation process. That doesn’t belong in the Downloads folder.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Thanks for the response. I made another discovery. The app CAN actually access the Downloads folder. But ONLY the first time it's run when the helper is installed. Then, it doesn't work again unless I launchctl unload and load.

Also, I realize there is a bigger problem. Let me expand a bit on this, the download location is user selectable, since the installer packages may be quite large and users like to download them to an external volume. This is an important feature for our app, and unfortunately external volumes suffer from the same problem as the Downloads folder.

(1) Is this expected behavior?
(2) Is there any way around this?

Thanks.

External volumes are covered by a different TCC privilege. In System Preferences > Security & Privacy > Privacy > Flies and Folders > Your App Name, you’ll see either Downloads Folder or Removable Volumes.

The app CAN actually access the Downloads folder. But ONLY the first time it's run when the helper is installed. Then, it doesn't work again unless I launchctl unload and load.

I’m confused by what you mean by “app” in this context. What I’d do in your situation is add dummy code to the app itself that tries to access the file in question. That’ll confirm that TCC is behaving itself for your app, ignoring your privileged helper tool. Because if that’s not working you have bigger problems (-:

The next thing I recommend is that you test on a ‘fresh’ machine. TCC can sometimes get itself tied up in knots on your development machine. I generally use a VM for this, restoring it from a snapshot (that I took before it ever saw my app) between each test run.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Thanks for the VM suggestion - I will research that. In the mean time I tested it on a "fresh" clone of a Catalina drive I happen to have.

I’m confused by what you mean by “app” in this context.

What I meant by this specifically is the helper tool, which the app calls via XPC. I guess my thinking was that the helper tool would automatically be inheriting the TCC privilege.

I did as you suggested and added code to the app itself to access the file on the removable disk. Indeed, the first time I run the app, a dialog asks me for permission to access removable disks (which it didn't before, and I can see the app has been successfully added to the Security 'Files and Folders' area) and it copies/renames the file successfully. However the helper tool still fails to run the file using installer.

On the fresh Catalina disk, I get the exact same behavior. The helper tool can access and install the package successfully unless it's on a removable drive (or in Downloads folder etc.). So this issue does not seem to be specific to the development machine.

Because if that’s not working you have bigger problems

Gulp...

Further to my last reply, I tried to work-around this by simply copying the installer package from the removable disk prior to running it. And...

I've now discovered an 'even worse' problem, which is that the installation does not work ("install failed. Authorization is required to install the packages.") if the install -target is a removable disk. The symptoms are the same, it works only the very first time the privileged helper is installed and does not work again after that.

For anyone else reading this, note that the title of this thread is misleading, because I mistakenly thought it could be fixed by manually checking the box in Full Disk Access.

Is there any way to give the PrivilegedHelper access to removable volumes? If not, is there any different strategy I can use to run an installer package from my app? (aside from just opening the package in the GUI installer.app)

For context, this is a download and installation manager, that is used to install many different packages, some quite large (plugins, additional content, etc..) for our main program.

I've now discovered an 'even worse' problem

Well, that’s not good.

Unfortunately I don’t have an easy answer for you here. If you look at my On File System Permissions post you’ll see that it discusses the concept of responsible code. I suspect that TCC is not able to follow the responsibility chain from your privileged helper tool to your app. However, it’s hard to say that definitively without more research, and I don’t have time for that here on DevForums. I recommend that you open a DTS tech support incident and we can pick things up in that context.

And fair warning: The result of that research might just be “This just doesn’t work on current systems and your only option is to file a bug.” )-:

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Ok, I will take your suggestion and open a DTS.

At this point it seems like the question is at least in part easy to define: Should a privileged Helper be able to access a removable volume? Is the answer yes, or no?

Does it work for other people? Try making a privileged helper according to EBAS and see if it can, say, access a file on a removable volume (or, the Downloads or Documents folder).

Now with further testing here, the app CAN access removable volumes the first time it's run when the helper is installed, AND in my current testing it is also working the SECOND time (??). If I then close the app and run it again, a THIRD time, then it no longer works. There is no way at all to make it work after this, with the exception of manually unloading and uninstalling the daemon and helper.

I don't understand this. How can I develop an app that will stop working for the user with no way to fix it?

Did you ever have any luck with this?

PrivilegedHelper has no access to Downloads folder unless the user manually enables Full Disk Access
 
 
Q