I’m looking for clarification on supported public API semantics on macOS.
Target runtime:
- arm64 macOS 15.4.1
- build 24E263
The question is whether macOS provides a supported public API, or a supported composition of public APIs, that allows an external launcher or OS observer to:
-
Obtain and freeze an identifier I(P) for the exact post-exec occurrence of a process P before P sends a security-sensitive IPC request.
-
Later obtain OS-supplied sender identity J(M) for an individual XPC or raw Mach message M.
-
Determine, using documented comparison semantics, whether J(M) identifies the same process-image occurrence as I(P).
The comparison needs to distinguish cases such as:
- two concurrent processes with the same UID and signed code;
- exec replacement while retaining a PID;
- exit, restart, and PID reuse;
- stale or queued messages;
- a transferred XPC endpoint or Mach send right;
- an undelegated proxy.
PID, UID, code-signing identity, launch labels, connection/right possession, or “first message wins” are not sufficient by themselves for this requirement.
I have looked at mechanisms including:
- suspended process launch;
- task identity tokens;
- Endpoint Security AUTH_EXEC process identity;
- XPC per-message sender identity;
- SecCodeCreateWithXPCMessage;
- Mach audit trailers.
What I have not found is public documentation defining a common process-occurrence identity and a supported comparison procedure across the pre-IPC and later message-sender surfaces.
A token generated by the target and sent in its first message also would not solve this specific problem, because the process claiming the token has already selected itself before the external observer binds the expected occurrence.
Is there a supported public way to achieve this?
If so, I would appreciate pointers to:
- the relevant public APIs;
- the canonical comparison procedure;
- required entitlements, task rights, TCC permissions, root privileges, or system-extension requirements;
- documented behavior across exec, exit, restart, and PID reuse;
- relevant Apple documentation or sample code.
If there is no supported public API that provides this property, confirmation of that would also be very helpful.
I’m specifically interested in documented, supported public API semantics rather than private SPI or undocumented implementation behavior.
It’s better to reply as a reply, rather than in the comments; see Quinn’s Top Ten DevForums Tips for this and other titbits.
With posix_spawn you can start the process in a suspended state (POSIX_SPAWN_START_SUSPENDED). That ensures that the PID you get back can’t bee reused and that it can’t have done any IPC yet. At that point you can map the PID returns to a task (task_for_pid or, better yet, task_name_for_pid) and from there get its audit token (task_info with TASK_AUDIT_TOKEN). You can then compare that to the audit token you get from the Mach message trailer.
However, I must stress that you’re skating on very thin compatibility ice here. While these are all APIs, they are very tightly bound to the kernel implementation. This makes it much harder for us to maintain our usual compatibility guarantees, meaning that your code is more likely to break than, say, a typically app. Moreover, if things do break it’s hard to guarantee that there will be a alternative path to the same result.
What sort of product are you creating here? Do you plan to ship it to a broad group of users? Or is this something you’re building for your internal use?
Have you looked at the new es_new_descendants_client mechanism we added in macOS 27 beta? If you’re focus is on child processes, that might offer a better path forward.
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"