Entitlement for extension to have read-only access to host's task?

Hi all,

I'm building an iOS app extension using ExtensionKit that works exclusively with its containing host app, presenting UI via EXHostViewController.

I'd like the extension to have read-only access to the host's task for process introspection purposes. I'm aware this would almost certainly require a special entitlement.

I know get-task-allow and the debugger entitlement exist, but those aren't shippable to the App Store. I'm looking for something that could realistically be distributed to end users.

My questions:

  1. Does an entitlement exist (or is one planned) that would grant an extension limited, read-only access to its host's task—given the extension is already tightly coupled to the host?
  2. If not, is this something Apple would consider adding? The use case is an extension that needs to inspect host process state without the ability to modify it.
  3. Is there a path to request such an entitlement through the provisioning profile process, or is this fundamentally off the table for App Store distribution?

It seems like a reasonable trust boundary given the extension already lives inside the host's app bundle, but I understand the security implications. Any insight appreciated.

Thanks!

Answered by DTS Engineer in 873213022

Thanks for the extra context. At this point I feel comfortable talking about technical stuff…

Oh wait, there’s one more business-y thing. My focus is on technical stuff. I don’t work for App Review and can’t make definitive statements about their policies.

OK, now let’s talk technical…

Mach is a capability-based system [1]. For you to get access to a Mach port, someone who already has access must share their access with you. So, who has access? And how can you convince them to share?

In this case only two entities have access:

  • The ‘system’
  • The target process itself

There’s no way to convince the system to share its access, at least on iOS [2]. So the only option is to get the target process to give you access to itself.

In theory, this should be trivial:

  1. Your app calls mach_task_self to get a send right for its control port.
  2. It then sends your extension a copy of that right via XPC.

In practice, there are complications.

IMPORTANT I’ve never tried this sort of thing on iOS, so I’ve no idea whether it’ll work at all. And if it does, I’m concerned about its long-term binary compatibility. I’ll come back to that point below.

Task control port send rights are a serious security concern, and thus Apple is invested in limiting their use. My primary experience with this is an macOS, where the system supports variants of this port that have more limited uses. You can see evidence for this in various places:

  • In <mach/task_special_ports.h> there’s a variety of special ports that represent the task port with limitations, for example, TASK_INSPECT_PORT.
  • Conforming to Mach IPC security restrictions discusses task identity tokens, as a way for the system to pass an exception handler the identity of a task without passing it a task control port.

These limitations have rolled out steadily over the years, and it wouldn’t surprise me if that process continued into the future. My experience is that, on macOS, we go the extra mile to provide some sort of ‘escape hatch’ so that existing programs can continue working. That’s less common on iOS, where we just don’t expect iOS apps to be monkeying around with Mach IPC.

Note The documentation for the com.apple.security.hardened-process.platform-restrictions entitlement contains this chestnut: “instruct the system to protect against particular attacks that target … Mach messaging.” At some point someone will ask me what that actually means. Fortunately that hasn’t happened yet (-:

And all of this is in addition to my general warning about Mach APIs. Mach APIs are supported, but they’re tightly bound to the kernel and thus tend to have more compatibility problems than higher-level APIs. I’ve been warning folks about this for decades. I think this example is instructive. It’s not specific to the Mach IPC subsystem, but that’s kinda the point: All of Mach is like this.

So, you should feel free to take this idea for a spin. If it works in development, use TestFlight to confirm that it works for apps targeting the App Store. If so, you then have to think carefully about whether you want to continue down this path given the potential compatibility pitfalls.

I’d love to know how far you get, so please do update this thread as you go.

Share and Enjoy

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

[1] In this sense of that phase.

[2] On macOS you have options, like getting a list of tasks from the host or everyone’s favourite [3] task_for_pid. Neither is an option on iOS.

[3] Well, not everyone’s favourite. I think it’s safe to assume that the Apple engineers who are responsible for platform security are not fans (-:

As things currently stand, ExtensionKit on iOS [1] requires that the host and container apps be the same, that is, an app can only load extensions that are located within the app.

Given that reality, does your high-level goal still make sense?

Share and Enjoy

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

[1] This limitation does not apply on macOS.

100%. I specifically only want the extension to have access to it’s host.

OK.

I was gonna ask if you were OK with this just being restricted to development-signed apps, but then I re-read your original post and saw this:

I'm looking for something that could realistically be distributed to end users.

So, next question: Do you care if this is limited to devices with Developer Mode enabled? Or do you want it to work regardless of that?


For context, there are two parts to your question:

  • What’s currently possible?
  • Would could Apple enable in the future?

Your answers to these questions inform both parts. If you want to explore what’s currently possible, you need to realistic tests. If something works with a development-signed app on a Developer Mode device but your target audience is a distribution-signed app on all devices, that’s not a useful data point.

In terms of The Future™, that’s not something I can address here. As I explain in tip 3 in Quinn’s Top Ten DevForums Tips, I encourage folks to file enhancement requests for the features they need. But in this case, this stuff is extremely security sensitive, meaning that any ER is going to struggle to get traction. So, I want to get a better understanding of your goals so that I can advise you as to how best to position this.

Share and Enjoy

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

Much prefer it to work without developer mode. But I'll take what I can get today, and possible make a feedback request for more.

To be a bit more clear, I'm doing research on how far I can get today, with the goal of trying to get this to a place where it could be in AppStore distributed apps some day in the future.

Accepted Answer

Thanks for the extra context. At this point I feel comfortable talking about technical stuff…

Oh wait, there’s one more business-y thing. My focus is on technical stuff. I don’t work for App Review and can’t make definitive statements about their policies.

OK, now let’s talk technical…

Mach is a capability-based system [1]. For you to get access to a Mach port, someone who already has access must share their access with you. So, who has access? And how can you convince them to share?

In this case only two entities have access:

  • The ‘system’
  • The target process itself

There’s no way to convince the system to share its access, at least on iOS [2]. So the only option is to get the target process to give you access to itself.

In theory, this should be trivial:

  1. Your app calls mach_task_self to get a send right for its control port.
  2. It then sends your extension a copy of that right via XPC.

In practice, there are complications.

IMPORTANT I’ve never tried this sort of thing on iOS, so I’ve no idea whether it’ll work at all. And if it does, I’m concerned about its long-term binary compatibility. I’ll come back to that point below.

Task control port send rights are a serious security concern, and thus Apple is invested in limiting their use. My primary experience with this is an macOS, where the system supports variants of this port that have more limited uses. You can see evidence for this in various places:

  • In <mach/task_special_ports.h> there’s a variety of special ports that represent the task port with limitations, for example, TASK_INSPECT_PORT.
  • Conforming to Mach IPC security restrictions discusses task identity tokens, as a way for the system to pass an exception handler the identity of a task without passing it a task control port.

These limitations have rolled out steadily over the years, and it wouldn’t surprise me if that process continued into the future. My experience is that, on macOS, we go the extra mile to provide some sort of ‘escape hatch’ so that existing programs can continue working. That’s less common on iOS, where we just don’t expect iOS apps to be monkeying around with Mach IPC.

Note The documentation for the com.apple.security.hardened-process.platform-restrictions entitlement contains this chestnut: “instruct the system to protect against particular attacks that target … Mach messaging.” At some point someone will ask me what that actually means. Fortunately that hasn’t happened yet (-:

And all of this is in addition to my general warning about Mach APIs. Mach APIs are supported, but they’re tightly bound to the kernel and thus tend to have more compatibility problems than higher-level APIs. I’ve been warning folks about this for decades. I think this example is instructive. It’s not specific to the Mach IPC subsystem, but that’s kinda the point: All of Mach is like this.

So, you should feel free to take this idea for a spin. If it works in development, use TestFlight to confirm that it works for apps targeting the App Store. If so, you then have to think carefully about whether you want to continue down this path given the potential compatibility pitfalls.

I’d love to know how far you get, so please do update this thread as you go.

Share and Enjoy

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

[1] In this sense of that phase.

[2] On macOS you have options, like getting a list of tasks from the host or everyone’s favourite [3] task_for_pid. Neither is an option on iOS.

[3] Well, not everyone’s favourite. I think it’s safe to assume that the Apple engineers who are responsible for platform security are not fans (-:

Great stuff. I'm going to give it a go. You're not the first to mention to me that the host app should try and share its port. I'm curious to see how far I'll get. First step is to figure a way to get the underlying xpc_connection_t from an NSXPCConnection. I know there's a private getter, but that'll just get me so far.

Thanks again.

First step is to figure a way to get the underlying xpc_connection_t from an NSXPCConnection.

There isn’t a supported way to do that.

I presume that you want to do that so that you can transfer Mach ports over the connection. If so, there’s an alternative path:

  1. Create an XPC dictionary.
  2. Add a send right to the dictionary using xpc_dictionary_set_mach_send.
  3. That dictionary is an xpc_object_t, so you can send it over the NSXPCConnection using NSXPCCoder.
  4. On the receiving side, get the send right from the XPC dictionary using xpc_dictionary_copy_mach_send.

Or at least that should work. I’ve never actually tried it (although I have exercised step 3 with other types of xpc_object_t).

I recommend that you prototype this on your Mac using a loopback connection, as explained in TN3113 Testing and debugging XPC code with an anonymous listener. And you can use lsmp (see the lsmp man page) to make sure that you got all the Mach port right reference counting correct (-:

Share and Enjoy

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

Entitlement for extension to have read-only access to host's task?
 
 
Q