Thank you, we have filed a report with more details under the id FB11683618.
Post
Replies
Boosts
Views
Activity
TL;DR If you want to use the above entitlement in the app store, you will at least have to appeal the rejection (and it might still be turned down).
A quick summary for the sake of future developers reading this: We eventually opened a DTS case to discuss options as advised by app review. The discussion concluded that there are no good options without the above entitlement, the only fix that could be accepted into the app store under this policy being to embed needed trust roots in the code instead of accessing them through the OS.
We verified that narrowing the entitlement to just the lock file
<key>com.apple.security.temporary-exception.files.absolute-path.read-write</key>
<array>
<string>/private/var/db/mds/mds.lock</string>
</array>
is sufficient and this was confirmed by DTS, but this entitlement was likewise rejected by app review as requesting "read-write access to read-only system location".
As app review did not respond to requests to further clarify their policy, we verified that on BigSur a sandboxed app running as root (in this case a network extension) can write to the /private/var/db/mds/mds.lock file (and indeed even other files like /private/var/db/mds/mds-test.lock) and pointed this out to challenge the classification as "read-only system location". After further review, this didn't change the rejection outcome. We appealed the decision and let the case run for ten days without response other than an initial notification that it was being looked at.
Eventually, we were pressed by external deadlines - as you can see this has been dragging out for about a month now - and submitted the alternative workaround that embeds trust roots in the code, which I believes withdraws the appeal. Without the entitlement, our app has been accepted. Clearly, this is an inferior solution in terms of both maintenance and security, but for now it is our only option.
In our app, the workaround temporary exception suggested by Quinn
Pending a fix, you can work around the bug by adding a temporary exception entitlement to your sysex:
<key>com.apple.security.temporary-exception.files.absolute-path.read-write</key>
<array>
<string>/private/var/db/mds/</string>
</array>
has been rejected by Mac App Store app review with the comment
Value "/private/var/db/mds/" requests read-write access to read-only system location.
Our deployment target is 10.15 so a workaround is necessary despite the issue being fixed on BigSur. I referenced both Quinn's post as well as the bug number in the submission.
As advised, I tried to replace the above .read-write entitlement with a .read-only entitlement, but this does not seem sufficient to prevent the underlying bug.
Could I get confirmation or clarification whether .read-write is indeed necessary?
(I was going to open a DTS incident but then reconsidered since the form directs you to check the developer forums first and, well, I knew of this forum thread right here :) )
I now noticed that this issue also occurs independent of using xcconfig-defined variables. Skipping step two in the "Steps to reproduce" and using hardcoded (but different) bundle identifiers for the two configurations in step five will show the same behavior.
On the other hand, if you use only a single configuration setting the bundle identifier to $(BUNDLE_ID) then the first build after changing the value of BUNDLE_ID in the xcconfig file will always fail as above, trying to copy the old bundle id - so this isn't only a matter of using different configurations either.
Dear meaton, Dear eskimo,
Thank you for your quick and helpful responses, as always!
I tried the steps you outlined, and indeed the sandbox no longer gets in the way once I run from /Applications!
Some further info, for the benefit of future readers: It is not enough to drag the app over from the products folder inside xcode (which will only create a link), but you have to actually move or copy the .app file.
At least on Catalina it is still necessary to include a com.apple.security.temporary-exception.files.absolute-path.read-write entitlement for /private/var/db/mds/, or else even SecCodeCopySelf fails, which I believe is because of the bug linked above.
I do have reservations about deploying an app that relies on the Container app and
the Network System Extension communicating back and forth.
I’ll provide some further information that would hopefully alleviate your concerns:
There are basically two kinds of messages we send: User-provided configuration information that the container app sends configuration information to the system extension, mostly about how to talk to our remote backend. This will only happen rarely, potentially only once when the first user starts and “activates” the product for the first time. This is what should ideally be protected from random apps messing with the configuration.
Status information sent from the system extension to the container app
The latter is
2a) about whether dns traffic is currently being intercepted, as this depends not only on the DNSProxy being active, but also on the system extension having a connection to our remote backend, and
2b) an event indicating that a flow has just been blocked. We use this to spawn a notification to inform the user. The system extension can’t spawn these notifications itself since, as you say, it is not running as the user.
In particular, we are not sending back and forth data about every individual flow, nor are we making decisions about whether to allow flows inside the container app. If no container app is connected via XPC, the system extension will still continue to work properly and do its job, it will simply be less visible to the user.
I think this is very similar to the SimpleFirewall example from WWDC linked above.
Alright, thanks for your thoughts on the matter! If we end up filing a bug report I will link it here :)
The quick answer is "Sandboxing because we want to (eventually) distribute via the Mac App Store".
(For testing, QA, and customer demos we are also handing out Developer ID signed versions, and these are sandboxed to be as close as possible to the Mac App Store version.)
Thanks for all this information!
The documentation pages of both Authorization Services and SFAuthorization show warnings that these cannot work in sandboxed apps since they allow privilege escalation.
Is there a way to do the same thing ("I just want to force the entry of an admin user/pass to protect an area of my app") in a sandboxed app (for example to be allowed into the mac app store)?
Pinging this post as suggested by @meaton
Dear Matt Eaton,
Thank you for your quick and helpful response, as always.
Indeed we are talking to our network extension by adapting what the SimpleFirewall app does to include a method like sendProviderMessage added to the ProviderCommunication protocol as you describe.
From your answer I would expect that the process of the network extension is terminated when the NEDNSProxyProvider disabled using the NEDNSProxyManager. Experimenting with the SimpleFirewall application, however, I see this process still alive after disabling the FilterProvider and even after stopping the debugging session in xcode (I set systemextensionsctl developer on to make running the network extension from the xcode debugger possible). From what I can see the process seems to keep running until a reboot, and then it is either launched again or not depending on whether the filter was enabled or disabled.
Adding an object that periodically logs that it is still alive to the network extension’s main.swift also shows that the process keeps running until a reboot. Hence my confusion about how to terminate the network extension process, since this doesn’t seem to be done by disabling the filter.
We are unsure whether this process continuing to run without interruption independently of enabling/disabling the ProxyProvider is something we can rely on, or whether the OS might at some point decide to terminate it since the provider that it belongs to has been disabled for some time.
Also, we are unsure about whether it is appropriate to do occasional communication with our backend from this process even when the ProxyProvider is disabled, for example to keep configuration up to date.
Thank you both, tartempion and meaton.
I was indeed planning to use a network extension (likely NEDNSProxyProvider to only filter dns traffic), but I didn't realize that once enabled and activated it will already be started automatically as you describe - I will experiment with this.
Consequently I don't need the companion app offering a UI to start before the user has logged in, since it isn't necessary to start the extension or configure it with the NEDNSProxyManager on every restart (as I previously thought).
Just a quick clarification @meaton:
Network System Extensions are not a target you can submit for the App Store. I assume you are talking about a System Extension target without accompanying app? If the System Extension is packaged together with a UI app, like the example SimpleFirewall app - https://developer.apple.com/videos/play/wwdc2019/714, then it is presumably fit for the App Store? (I remember this being mentioned in the WWDC2019 talk about system extensions) - https://developer.apple.com/videos/play/wwdc2019/702/