Supported macOS design for safely terminating an app-owned helper subtree?

I am designing a bounded local diagnostic helper for macOS. It would run only purpose-built helpers supplied by the application, not third-party or untrusted code. The design question is how to stop exactly those helpers and their descendants on timeout, without affecting an unrelated process or incorrectly reporting that cleanup is complete.

This is a public-API suitability question, not a report of a reproduced macOS bug. The intended diagnostic is not an antivirus or endpoint-detection product.

The required properties are:

  1. Identify each owned process by its lifetime and association with this helper run, not a numeric PID or process-group ID alone.
  2. Account for descendants across fork/exec, parent exit or reparenting, and process-group/session changes. Observing that a descendant escaped is not equivalent to preventing an escape.
  3. Terminate only the still-owned processes without a stale-identity race between checking ownership and signaling.
  4. Report completion only when all owned descendants have stopped and no new owned descendants can appear. Leader exit, IPC disconnection, or an unauthenticated empty process list would not be sufficient. Lost events or uncertain membership must leave the outcome inconclusive.

Which supported public API or service/containment architecture can provide these properties? If they cannot all be guaranteed, which constraint should be changed and what guarantee can the supported alternative actually provide?

I have reviewed the documentation for es_new_descendants_client and es_sync_client. The remaining questions are:

  • Is a descendant-scoped Endpoint Security client appropriate for this non-security-product diagnostic? If so, which documented entitlement and packaging route applies? I am asking about eligibility, not assuming it.
  • Does any supported design combine lifetime-safe control with containment of the whole owned subtree, including concurrent descendant creation? Merely receiving events would not establish that property.
  • What additional protocol, if any, makes a synchronization callback sufficient to establish complete termination when client destruction, event loss, and concurrent activity are possible? I am not treating that callback alone as proof that no owned process remains.

I can redesign around a helper that cannot create descendants if that is the supported approach. In that case, what supported mechanism enforces that restriction and what termination guarantees remain?

So far, a standalone C harness has passed eleven fabricated-input cases with assertions enabled. It exercised no Endpoint Security client, process-tree creation/enumeration/control, or application behavior. It is not a runtime reproducer for this API-design question and does not establish native lifecycle safety.

Pointers to documented guarantees, limitations, or an Apple sample would help me choose the architecture before preparing a narrowly scoped native test. I am not seeking private APIs or a way to disable platform protections. No logs, source archive, or binary is attached.

Is a descendant-scoped Endpoint Security client appropriate for this non-security-product diagnostic?

Yes. One of its intended use cases is exactly what you're describing.

If so, which documented entitlement and packaging route applies?

You'll need the com.apple.developer.endpoint-security.client entitlement, and your code will need to be embedded in a package.

Does any supported design combine lifetime-safe control with containment of the whole owned subtree, including concurrent descendant creation? Merely receiving events would not establish that property.

I'm not sure what you mean here. es_new_descendants_client ensures that you'll receive the events from all of your descendants, so, by definition, every process you receive an event from is one of your descendants.

What additional protocol, if any, makes a synchronization callback sufficient to establish complete termination when client destruction,

I'd need to understand what your actual threat model/concern here is.

event loss,

What are you actually concerned about here? In a properly designed es client, most auth events should be responded to with "cache=true", allowing the kernel to avoid repeated callouts asking you to approve activity you've already approved (or denied) in the past. This substantially reduces auth event volume.

In addition, es_set_deadline_min_milliseconds allows you to extend the deadline for arbitrarily long periods of time, allowing you to take as long as you want to process any auth requests (the calling process will block waiting on you).

and concurrent activity are possible?

I don't know what you mean here.

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

Supported macOS design for safely terminating an app-owned helper subtree?
 
 
Q