Supported macOS containment for a sandboxed worker after controller failure.

Subject: Supported macOS containment for a sandboxed worker after controller failure

I'm investigating an Apple Silicon/macOS architecture in which an untrusted, signed, sandboxed worker must be independently containable by a separate trusted supervisor.

The worker needs only a narrow authenticated communication channel. It requires no direct network access, external operational credentials, privileged file access or authority to launch helpers.

I understand that App Sandbox does not inherently prevent child-process creation, and that RLIMIT_NPROC alone does not prevent every form of execution delegation.

Could you clarify:

  1. Is there a public, supported macOS mechanism to deny all worker-originated subprocess creation and execution delegation at launch, while retaining one restricted communication channel?
  2. Alternatively, is there a supported mechanism for a surviving supervisor to identify, terminate and positively verify the complete execution domain of a worker, including any descendants, after its controller crashes or is suspended?
  3. What guarantees and limitations apply to stable identity, process exit, automatic relaunch and loss of the supervisor?

I'm specifically seeking supported operating-system guarantees, not private sandbox profiles, polling, heartbeat inference or best-effort process-tree enumeration.

The goal is to determine whether a bounded synthetic containment experiment is technically justified. No production implementation has been attempted.

Answered by DTS Engineer in 913523022
Written by levis46 in 913417022

I mean the complete execution scope originating from an untrusted worker

OK.

Written by levis46 in 913417022

the worker process itself, any child or descendant processes it starts, and any additional execution it can cause to run on its behalf through supported delegation mechanisms.

I’m gonna break this into two parts:

  • The process hierarchy
  • Any “supported delegation mechanisms”

The process hierarchy is something that Kevin has been discussing on other threads, and I’m gonna defer to him for that.

Regarding delegation, I don’t think there’s any good way for you to reason about this. Lemme illustrate this with two examples:

  • A process can use Virtualization framework to start a VM.
  • A process can use NSWorkspace to launch an app.

In the first case the Virtualization framework will clean up the VM when the process that created it terminates. In the second case that doesn’t happen. The underlying Launch Services machinery treats the launched app as a completely separate thing.

In both cases the actual work in done by system processes. However, the client doesn’t interact with those system processes directly. Rather, it calls the framework and the framework does whatever IPC is necessary to complete the task. The actual IPC mechanism is an implementation detail, not part of the API.

So, from your perspective:

  • You can’t block the process from using these frameworks.
  • You could potentially block a framework from performing its IPC, but you can’t do that without becoming deeply entangled with the framework’s implementation. This is going to be very brittle and certainly not something that DTS is gonna support.
  • You can’t, in the general case, know whether a specific framework cleans up on behalf of its clients. Indeed, this could vary within a framework. For example, within AppKit you’ll find that a window you create with NSWindow will get cleaned up but an app you launch with NSWorkspace won’t.

Taking a step back, I recommend that you have a read of TN2083 Daemons and Agents. It describes, in gory detail, how macOS’s execution context differs from that found on traditional Unix-y systems. This difference will significantly affect any attempt by you to limit the impact of code that you don’t trust.

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

First, a general point about sandboxing. I see a bunch of folks implement sandboxing via SBPL and I want to be clear that that’s not supported. See this thread for more about that.

Second, we generally recommend that folks adopt the new es_new_descendants_client mechanism that we added in macOS 27. There have been a lot of threads on the forums about this issue recently, and I recommend that you review them before continuing with this thread.

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

Thank you, Quinn. I've reviewed the descendant-scoped Endpoint Security mechanism and the related DTS discussion:

https://developer.apple.com/forums/thread/852760

That discussion confirms that Endpoint Security cannot preserve required authorisation denials throughout client loss and recovery using its APIs, including for descendant-scoped clients.

My remaining question is therefore specifically about supported containment independent of the enforcement client's continued operation.

Does macOS provide a public, supported mechanism that either:

  1. Restricts a sandboxed worker from creating or delegating execution outside its assigned domain, with those restrictions surviving controller failure; or
  2. Allows a surviving supervisor to positively establish termination of the complete predecessor execution domain, including descendants and delegated execution, before starting a replacement?

If neither guarantee is currently available through supported APIs, confirmation of that limitation would also be helpful.

I'm keeping network transmission and transport fencing as separate requirements.

Thank you for your guidance.

Written by levis46 in 912799022

1- Restricts a sandboxed worker from creating or delegating execution outside its assigned domain … ?

What do you mean by “associated domain”. That’s not a term from the Apple world [1].

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

[1] Well, except in this context, but I’m pretty sure that’s not what you meant (-:

Thank you, Quinn. You're right — “assigned domain” was my own imprecise terminology, not a macOS API concept. Apologies for the ambiguity.

By it, I mean the complete execution scope originating from an untrusted worker: the worker process itself, any child or descendant processes it starts, and any additional execution it can cause to run on its behalf through supported delegation mechanisms.

I am not assuming macOS provides an existing process-grouping or security-domain abstraction covering all of these.

The requirement is to establish one of two guarantees:

  1. Prevent the worker from creating or delegating additional execution in the first place, leaving only the original sandboxed worker and its narrowly authorised communication channel; or
  2. Provide a supported, OS-enforced way for an independent supervisor to identify, terminate and positively verify the end of all worker-originated execution before a replacement worker is allowed to run.

The critical failure case is loss of the worker's controller. A mechanism requiring that controller or an Endpoint Security client to remain operational would not independently satisfy the requirement.

I'm asking whether macOS exposes a supported mechanism for either guarantee, rather than proposing that such an execution domain already exists.

If neither is available, confirmation of that limitation would be equally helpful.

Thank you again for your guidance.

Written by levis46 in 913417022

I mean the complete execution scope originating from an untrusted worker

OK.

Written by levis46 in 913417022

the worker process itself, any child or descendant processes it starts, and any additional execution it can cause to run on its behalf through supported delegation mechanisms.

I’m gonna break this into two parts:

  • The process hierarchy
  • Any “supported delegation mechanisms”

The process hierarchy is something that Kevin has been discussing on other threads, and I’m gonna defer to him for that.

Regarding delegation, I don’t think there’s any good way for you to reason about this. Lemme illustrate this with two examples:

  • A process can use Virtualization framework to start a VM.
  • A process can use NSWorkspace to launch an app.

In the first case the Virtualization framework will clean up the VM when the process that created it terminates. In the second case that doesn’t happen. The underlying Launch Services machinery treats the launched app as a completely separate thing.

In both cases the actual work in done by system processes. However, the client doesn’t interact with those system processes directly. Rather, it calls the framework and the framework does whatever IPC is necessary to complete the task. The actual IPC mechanism is an implementation detail, not part of the API.

So, from your perspective:

  • You can’t block the process from using these frameworks.
  • You could potentially block a framework from performing its IPC, but you can’t do that without becoming deeply entangled with the framework’s implementation. This is going to be very brittle and certainly not something that DTS is gonna support.
  • You can’t, in the general case, know whether a specific framework cleans up on behalf of its clients. Indeed, this could vary within a framework. For example, within AppKit you’ll find that a window you create with NSWindow will get cleaned up but an app you launch with NSWorkspace won’t.

Taking a step back, I recommend that you have a read of TN2083 Daemons and Agents. It describes, in gory detail, how macOS’s execution context differs from that found on traditional Unix-y systems. This difference will significantly affect any attempt by you to limit the impact of code that you don’t trust.

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