Hardened XPC Services Don’t Prompt
Things get a bit more complicated if an attempt to access contact comes not from the application, but from its bundled XPC service, like explained in the video.
[…]
Luckily, smart folks at Apple thought of such scenarios, so macOS security subsystem (for simplicity, I will refer to it as TCC) understands that the AvatarService is trying to access contacts ON BEHALF of GitFinder application.
[…]
The application + XPC service combo build with hardened runtime fails to access contacts. Having proper sandbox entitlement defined, the XPC service requests access to contacts and passes that request to the application, just like it did before hardened runtime. However, this time around the TCC does not understand that the request comes from the XPC service on behalf of the application. Instead, it thinks the request comes from the application itself and hence checks if the application has required sandbox entitlement (AddressBook). Since the entitlement isn’t there, because the application does NOT need it at all, access to contact is denied.
[…]
The consequence of absence of absolutely unnecessary sandbox entitlement is the user consent dialog NOT being displayed at all. The user won’t even know the application would like to access contacts and the access will be permanently declined.
This probably happens for all the entitlements, not just the Contacts one. The same thing happened for a while with command-line tools on macOS 10.14 (except without the workaround). If not addressed, this will become a bigger issue in January, when the hardened runtime becomes a requirement.
Previously:
- Catalina Notarization
- Notarization Requirements Relaxed
- Annoying Catalina Security Features
- Hardened Runtime and Sandboxing
Update (2019-11-07): Felix Schwarz:
Bug: in #macOS 10.14/10.15 host apps needs to be given the same privacy entitlement as bundled XPC services - even if ONLY the XPC service needs it; eliminating THE key security benefit of sandboxed XPC services & increasing attack surface.
Apple’s Rosyna Keller says this is a feature, not a bug:
The issue here is better attribution in TCC. If App B is immediately passing data to App A, they both need the entitlement (because macOS knows you’re giving contacts to an unprivileged app).
This prevent attacks in which a malicious app asks a privileged app for private info only the latter is supposed to have access to.
I’m not convinced by this reasoning. Apparently, the requirement works this way for the TCC entitlements but not the traditional sandbox ones.
What if the XPC service only returns avatar images for email addresses?
In that case, a compromised GitFinder has no access to contacts data & only to those avatars for which the attacker already knows the email.
W/o separation of powers, an attacker gains unlimited access.
Update (2019-11-09): Jeff Johnson:
The sandbox allows the xpc service and the main executable to have different sandbox entitlements, which is how one can have the Contacts entitlement and the other not. In contrast, the hardened runtime depends only on the main executable of the app.
[…]
The app is still blocked unless the hardened runtime and the sandbox are in agreement. Here’s the catch: for better or worse, the hardened runtime and the sandbox use the same name for some entitlements. For example, they both use
com.apple.security.personal-information.addressbook
for the Contacts entitlement. As a consequence, if an app is both hardened and sandboxed, it’s impossible to give the Contacts hardened runtime entitlement to the [XPC service] without also giving the Contacts sandbox entitlement to the main executable!
I agree that the root problem for GitFinder is that the sandbox and hardened runtime use the same entitlement names for different purposes and with different inheritance rules.
In my opinion, I’m not sure that it is a problem. I don’t think the architecture of GitFinder reflects the intent behind Apple’s XPC API.
[…]
If the xpc passes Contacts info back the app, and network attackers compromise the app, then the network attackers have the Contacts info! The attackers may not have unlimited access to Contacts, but they still have some illicit access to Contacts. So you really haven’t solved the problem there.
This part I don’t agree with. I think it does make sense to use separate XPC services for privilege separation. In GitFinder’s case, the network and Contacts access are confined to separate XPC services. The app itself is isolated, so it shouldn’t get compromised. If it did, and the hardened runtime entitlements worked the same way as the sandbox, it would have only very limited access to Contacts through the XPC service, which is good.
The goal of the xpc service is not to limit the damage the app can do if it’s compromised, the goal is to prevent the app from getting compromised in the first place.
Why can’t it be both?
I’ve never said it’s related to notarisation, but in my experience it IS related to hardened runtime, because app+xpc without hardened runtime worked fine, while the same app+xpc with hardened runtime fails on the very same macOS version/build.
Furthermore, if it’s intentional (hence, a feature - “better attribution it TCC”) it would’ve been much easier if anyone from DTS had said that to me immediately, instead of having, like, seven months of back/forth correspondence…
… with two DTS guys, including filing a bug report (and reporting bug number back to DTS), running log stream for “com.apple.TCC” while running test applications and doing other things I was asked for, just to confirm noticed behaviour.
Alas, the TCC/privacy stuff is virtually undocumented and was only discussed in a cursory manner at WWDC. So it’s not surprising that is isn’t well understood inside Apple, either.
That’s actually what GitFinder is doing; its XPC service returns only image data for known email address (known from git commit) and nothing else.
Forcing compromised GitFinder to get something else back from XPC service would require compromising XPC service as well. But if GitFinder (application) has contacts entitlement, then all contacts data is available right away.
I have to agree with @mjtsai here and I think we “understand” the concept of “privilege separation with XPC services” the same way, but I accept I may be wrong. Anyway, there’s that video I referred to in the blog post
It actually starts at about 2:25 and is related to Preview.app architecture and different pieces it consists of, each having access to only limited resources.
Preview is probably chosen as an example of a know app. Anyway, this is how I thought of the whole concept: I will isolate access to contacts in a very small service, which can access contacts only…
… not disk, not network. If it is compromised (somehow, anyhow), access to contacts is there, but no contacts data can be written to disk or send over the network. And as a small binary, (I hope) the number of potential security holes is much smaller that in much larger app.
I think the case is that given
- App with the network entitlement
- Contained XPC service with the contacts entitlementthe system has to assume that App can access contacts too. XPC protects nothing: hijacked App it to give all the data.
My understanding is that privilege separation is still beneficial though: hijacked XPC cannot request App to give it contacts unless it is a part of the XPC connection protocol.
Update (2019-11-26): Jeff Johnson:
So the entitlement given to the xpc service applies directly to the xpc service. Indeed, if you enable the hardened runtime for the app target, it makes no difference. The hardened runtime of the app can neither allow nor prevent the unsigned dylib from getting loaded by the xpc service. The setting for Disable Library Validation on the app target has no effect at all on the behavior of the embedded xpc service. The xpc service hardened runtime does matter, at least for library loading.
[…]
In contrast to dyld, the Transparency, Consent, and Control (TCC) subsystem operates at the level of the app as a whole. The TCC database located at
~/Library/Application Support/com.apple.TCC/TCC.db
stores a reference to an app as a bundle identifier; it doesn’t distinguish between the app’s main executable and the embedded xpc service’s executable. Thus, for the purpose of resources access, all that matters is the hardened runtime on the main executable.