XPC communication between a sandboxed Network Extension and a privileged MachService

Hello,

Is it possible for a Network Extension (running in its sandbox) to act as a client for an XPC service hosted by a Launch Daemon (e.g., to offload data processing)? Are there any specific sandbox restrictions or entitlement requirements for this type of XPC communication?

Thank you in advance!

Answered by DTS Engineer in 881947022
Is it possible for a Network Extension … to act as a client for an XPC service hosted by a Launch Daemon … ?

Yes.

The trick is to use an app group. Sign your client with an app group ID and then, in the MachServices property of the launchd daemon, set the XPC endpoint name to be a ‘child’ of that app group ID. See the discussion in App Groups Entitlement.

App groups are a bit tricky on the Mac. See App Groups: macOS vs iOS: Working Towards Harmony for the full backstory.

Given that your client is sandboxed, it must claim access to that app group ID. And in that case I strongly recommend that you authorise that claim via a provisioning profile.

Your launchd daemon is (presumably) not sandboxed so it doesn’t need to claim access to the app group ID. However, if you decide to make that claim then my recommendation applies there as well: Authorise the claim with a provisioning profile.

If you claim access to an app group and don’t authorise that claim, the system will drop the entitlements-validate flag for your process, which can cause all sorts of weird issues. See App Groups: macOS vs iOS: Working Towards Harmony for more about that.

Share and Enjoy

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

Accepted Answer
Is it possible for a Network Extension … to act as a client for an XPC service hosted by a Launch Daemon … ?

Yes.

The trick is to use an app group. Sign your client with an app group ID and then, in the MachServices property of the launchd daemon, set the XPC endpoint name to be a ‘child’ of that app group ID. See the discussion in App Groups Entitlement.

App groups are a bit tricky on the Mac. See App Groups: macOS vs iOS: Working Towards Harmony for the full backstory.

Given that your client is sandboxed, it must claim access to that app group ID. And in that case I strongly recommend that you authorise that claim via a provisioning profile.

Your launchd daemon is (presumably) not sandboxed so it doesn’t need to claim access to the app group ID. However, if you decide to make that claim then my recommendation applies there as well: Authorise the claim with a provisioning profile.

If you claim access to an app group and don’t authorise that claim, the system will drop the entitlements-validate flag for your process, which can cause all sorts of weird issues. See App Groups: macOS vs iOS: Working Towards Harmony for more about that.

Share and Enjoy

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

Thanks for the detailed explanation and tips!

Could you please help with two architectural follow-up questions regarding the lifecycle and data flow:

  1. Boot-time execution and User Sessions:

In Apple's examples, the Network Extension is initially installed and activated via a Container App running within a user session. However, the extension itself runs as root. Assuming the user has approved the extension and the configuration is saved, will macOS automatically bootstrap this Network Extension at boot-time (before any user logs in)? We need to ensure that our global launchd daemon and the Network Extension can establish this App Group-based XPC connection and start filtering traffic regardless of active user sessions.

  1. Confirming the IPC Roles:

Given your suggestion to set the MachServices property in the launchd daemon, am I correct in assuming the recommended architecture is strictly:

Launch Daemon = XPC Listener / Server (handling complex analysis)

Network Extension = XPC Client (acting purely as a data provider pushing intercepted flows to the daemon)

Is there ever a valid use case where these roles should be reversed in a system-wide filtering context, or is the Daemon-as-Listener the absolute standard here?

Thanks a lot for your help!

will macOS automatically bootstrap this Network Extension at boot-time

Yes.

Is there ever a valid use case where these roles should be reversed … ?

It depends.

There are some things that are most definitely problematic. For example, in macOS’s layered architecture the client can’t be ‘below’ the server. For example, you can’t have a daemon client connect to an agent server, or an agent client connect to a server within an app.

You’ve already highlighted one key reason why this is problematic: A daemon can run when no user is logged in, so there might be no agent to connect to. Similarly, you can have multiple login sessions, so the connection could be ambiguous.

Now in your case you have a daemon and a NE sysex. The latter acts very much like a daemon. Specifically, it runs in the same global context as a launchd daemon. So, in theory you could have the daemon connect to the NE sysex. In reality though, the design you proposed, where the NE sysex connects to the daemon is the most sensible.


If you haven’t already done so, I strongly recommend that you read TN2083 Daemons and Agents. While it’s old, and definitely needs an update, its core ideas are still valid, and it’ll really help you understand how these parts fit together.

Share and Enjoy

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

Thanks a lot for the help!

Since both the Launch Daemon and the Network Extension start at boot-time before user login, is there a guaranteed initialization order between them? Specifically, is one guaranteed to be fully bootstrapped before the other, or should I treat their startup as a race condition?

Thank you again.

is there a guaranteed initialization order between them?

No, but that doesn’t matter because the launchd on-demand architecture defines away the sorts of ordering problems that plague other systems. If your NE sysex messages your launchd daemon, the system will start the daemon so that it can service the request.

Share and Enjoy

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

thank you for the help!

XPC communication between a sandboxed Network Extension and a privileged MachService
 
 
Q