Processes & Concurrency

RSS for tag

Discover how the operating system manages multiple applications and processes simultaneously, ensuring smooth multitasking performance.

Concurrency Documentation

Posts under Processes & Concurrency subtopic

Post

Replies

Boosts

Views

Activity

Processes & Concurrency Resources
General: DevForums subtopic: App & System Services > Processes & Concurrency Processes & concurrency covers a number of different technologies: Background Tasks Resources Concurrency Resources — This includes Swift concurrency. Service Management Resources XPC Resources Share and Enjoy — Quinn “The Eskimo!” @ Developer Technical Support @ Apple let myEmail = "eskimo" + "1" + "@" + "apple.com"
0
0
1.7k
Jul ’25
ExitTimeOut appears to be capped at 60 seconds, and ExitTimeOut 0 kills immediately
On macOS 27.x (Apple silicon) I've been measuring how launchd stops a job, and two behaviors don't match the documentation. Method: a throwaway job whose script traps SIGTERM and logs it, bootstrapped with different ExitTimeOut values, then stopped with launchctl bootout while timing when the process dies. Observed (LaunchAgent in the gui domain; the same results in the system domain with a LaunchDaemon): ExitTimeOut 45 -> `launchctl print` reports 45; SIGTERM, then SIGKILL at 45 s ExitTimeOut 61 -> reports 60; SIGTERM, then SIGKILL at 60 s ExitTimeOut 90 -> reports 60; SIGTERM, then SIGKILL at 60 s ExitTimeOut 120 -> reports 60; SIGTERM, then SIGKILL at 60 s ExitTimeOut 0 -> reports 0; SIGKILL after ~0.1 s, SIGTERM never deliveredman launchd.plist says of ExitTimeOut: "The amount of time launchd waits between sending the SIGTERM signal and before sending a SIGKILL signal when the job is to be stopped. The default value is system-defined. The value zero is interpreted as infinity and should not be used, as it can stall system shutdown forever." So: is there a 60-second ceiling on ExitTimeOut? It isn't documented that I can find, and it applies in both domains. And is zero meant to be "infinity" as documented, or an immediate SIGKILL as observed? Finally, is there a supported way for a service to be given more than 60 seconds to exit when launchd stops it — or is 60 seconds simply the maximum? Happy to file a Feedback with a minimal repro if that's useful.
2
0
149
16h
What happens after BGContinuedProcessingTask "expires"?
If I create a BGContinuedProcessingTaskRequest, register it, and then "do work" within it appropriately reporting progress, and before my task has finished doing all the work it had to do, its expirationHandler triggers... does the task later try again? Or does it lose the execution opportunity until the app is next re-launched to the foreground? In my testing, I never saw my task execute again once expired (which suggests the latter?). I was able to easily force this expiry by starting my task, backgrounding my app, then launching the iOS Camera App. My example is just using test code inspired from https://developer.apple.com/documentation/backgroundtasks/performing-long-running-tasks-on-ios-and-ipados let request = BGContinuedProcessingTaskRequest(identifier: taskIdentifier, title: "Video Upload", subtitle: "Starting Upload") request.strategy = .queue BGTaskScheduler.shared.register(forTaskWithIdentifier: taskIdentifier, using: nil) { task in guard let task = task as? BGContinuedProcessingTask else { return } print("i am a good task") var wasExpired = false task.expirationHandler = { wasExpired = true } let progress = task.progress progress.totalUnitCount = 100 while !progress.isFinished && !wasExpired { progress.completedUnitCount += 1 let formattedProgress = String(format: "%.2f", progress.fractionCompleted * 100) task.updateTitle(task.title, subtitle: "Completed \(formattedProgress)%") sleep(1) } if progress.isFinished { print ("i was a good task") task.setTaskCompleted(success: true) } else { print("i was not a good task") task.setTaskCompleted(success: false) } } try? BGTaskScheduler.shared.submit(request) Apologies if this is clearly stated somewhere and I'm missing it.
5
0
597
18h
SecCodeCreateWithXPCMessage: sender identity across concurrent receives, exec, and deferred replies
I am evaluating a local macOS C XPC design. The target under consideration is macOS 27.0.1, build 26A434, on Apple silicon. This is a source-design question; I have not run a reproducer or established that the public source below matches that OS build. The public SecCode.h comment describes SecCodeCreateWithXPCMessage as obtaining a code reference for the sender of the supplied XPC message using associated audit identity. The implementation at Apple Security commit 97c3a4296c1ea06b0fe1877a7e616aa84450b5b2 obtains the dictionary's remote connection, takes that connection's audit token, and uses it for code lookup: https://github.com/apple-oss-distributions/Security/blob/97c3a4296c1ea06b0fe1877a7e616aa84450b5b2/OSX/libsecurity_codesigning/lib/SecCode.h https://github.com/apple-oss-distributions/Security/blob/97c3a4296c1ea06b0fe1877a7e616aa84450b5b2/OSX/libsecurity_codesigning/lib/SecCode.cpp Function anchor in both files: SecCodeCreateWithXPCMessage. I am treating this as a question about the supported API contract, not evidence of a vulnerability or proof of installed implementation. For an actual received C XPC dictionary M, retained for deferred processing, I need to understand the supported identity and reply guarantees: Does SecCodeCreateWithXPCMessage(M, ...) resolve audit identity fixed to M's original sender occurrence, or can the associated connection's identity at lookup time differ? In particular, what is guaranteed if another message arrives or processing occurs concurrently on another queue? If the sending process performs exec before the lookup, or after lookup but before a reply, what does the resulting SecCode reference identify? Is there a documented supported way to distinguish the original message-sending occurrence and executable from a later executable or replacement peer without using PID-based reconstruction or private XPC APIs? If I retain M and later use its supported C reply context, does the reply remain addressed to that same original sending occurrence? What are the documented effects of connection invalidation, exec, forwarding/delegation of relevant rights and outstanding aliases? I am not assuming that retaining M or the returned SecCode reference locks peer identity or revokes other holders. If these APIs do not jointly provide those guarantees, which public API and ownership pattern should a design use to validate the actual eventual reply recipient before sending sensitive data? A statement that a guarantee is unavailable or requires a different design would also help. Please distinguish C XPC behavior from Swift XPCReceivedMessage; I am not assuming an undocumented conversion between them. Could you point to the applicable documentation and supported macOS versions, and clarify whether the cited public source revision is representative of the target? If exact-build behavior cannot be established publicly, please identify that limitation. This question concerns transport identity and context lifetime only. A valid code identity would still need separate application authorization; I am not asking XPC to issue role, run or resource authority. I would prefer a documented contract over an inference from a successful test. I can prepare a separately scoped minimal example if one is necessary, but no executable example is included in this question.
5
0
179
2d
Title: Supported OS-enforced restriction of Keychain access while retaining App Sandbox and App Group UDS
I’m designing a small, controlled macOS test harness. Two separately signed, sandboxed applications communicate through a UNIX-domain socket in an App Group container. They run as non-root processes in a GUI user session. One application also launches a child that inherits its sandbox and an existing socket descriptor. Is there a documented, supported OS policy that preserves this IPC arrangement while preventing the test processes from retrieving, using or modifying credentials, including items in their own Data Protection Keychain access groups and reachable file-based keychains? The policy must also prevent creating credential stores/items outside the permitted test resources. Using a macOS-style TeamID-prefixed App Group avoids that group providing Keychain sharing, but does not establish denial of the remaining Keychain operations. Empty stores, avoiding API calls and relying on users refusing prompts are insufficient for this requirement. If a different execution context or isolation architecture is required, could you identify the supported mechanism and relevant documentation? I’m seeking platform guidance, without relying on private APIs or unsupported custom sandbox profiles.
3
0
290
3d
Supported diagnosis for posix_spawn EPERM when launching a sandboxed local QA host
On macOS 15.7.9 (24G830), arm64, using Xcode 16.4 (16F6), a locally built QA host fails to launch through LaunchServices using open -W. The recorded signature is ad hoc, with no TeamIdentifier; its only recorded effective entitlement is com.apple.security.app-sandbox=true. The historical launch returned -10810. Correlated logs report posix_spawn: Operation not permitted (errno 1). Host entry was not observed. A packaging revision embedded the same Info.plist in __TEXT,__info_plist. Recorded signature verification succeeded, but the next launch produced the same rejection. The responsible policy remains unidentified; these observations are not an independently validated minimal reproducer. What supported diagnostic procedure can identify the policy responsible for this rejection without disabling security protections or using an alternative launch route?
1
0
113
3d
Keeping every descendant of a sandboxed XPC service’s worker inside its lifetime (fork, double-fork, setsid)
Apple DTS case 22893354: forum post and reply Apple asked for the question as a Developer Forums post, then a reply to the case email with the post URL. Nothing below has been posted or sent. 1. Forum post Post at https://developer.apple.com/forums/ (signed in, "Ask a question"). Suggested tags: XPC, App Sandbox, Endpoint Security Attach: fixtures/egress_guard/hp04/apple-descendant-sample/main.c, renamed to main.txt if the forum refuses .c. Title Keeping every descendant of a sandboxed XPC service's worker inside its lifetime (fork, double-fork, setsid) Body We are designing a macOS app that runs an unmodified third-party command-line tool for one task at a time. The plan is an app-bundled, sandboxed XPC service that launches the tool as a child process. The tool is not ours, so we have to assume it may fork without exec, double-fork, and call setsid(). For each run we need one guarantee: after the run ends, every process the tool created has stopped. "Ends" includes the XPC service crashing and the host app crashing, not only a clean cancel. If we cannot prove that, we cannot report the run as finished. What we have looked at so far: Killing the process group. A child that calls setsid() is no longer in the group. launchd's process-group cleanup for the job. As we read launchd.plist(5), that also covers the process group only. Tracking pids from fork and exit notifications, including Endpoint Security. Notifications can be dropped, and pids can be reused, so a list rebuilt from events is not proof that nothing is left. The attached sample shows the process shape without any sandbox or XPC. It starts a worker, the worker double-forks, and the grandchild calls setsid() and keeps writing to a log after the original process has exited. On macOS 15.6.1 the descendant shows parent pid 1 and its own session, and it keeps writing until it finishes on its own: // worker: fork twice, let the intermediate processes exit if (fork() > 0) _exit(0); if (fork() > 0) _exit(0); setsid(); // leaves the original process group and session for (int i = 0; i < 8; i++) { // append "tick i pid ppid" to the log, ppid is now 1 usleep(200000); }Build with cc -Wall -Wextra -Werror -o DescendantOutlivesParent main.c and run ./DescendantOutlivesParent /tmp/descendant-log /tmp/descendant-ready. Questions: Is there a supported mechanism that ties every descendant of a process started by an XPC service, including ones that called setsid(), to the lifetime of that service, so that they are terminated when the service exits or crashes? If the service is sandboxed, does sandbox inheritance (children inherit the parent's sandbox) also give us a way to find or terminate those descendants, or does it only restrict what they can do? If neither, what does Apple recommend for running an untrusted command-line tool where leftover descendants must be ruled out? For example, is a separate launchd job per run, a different process-management API, or Endpoint Security authorization the intended route? Can that mechanism be combined with per-run file access (one input folder and one scratch folder per run), without giving the tool a shared container or network access? We would rather learn that a guarantee is not available than build on an assumption, so a "this is not supported" answer is also useful to us. 2. Reply to the DTS email Reply to Apple's case email (keep the subject) after the post is live: Case-ID: 22893354 Hello, Thank you. I posted the question on the Developer Forums here: <FORUM POST URL> The sample project is attached to the post. There is nothing private in it. Best regards, <NAME>
1
0
67
3d
Supported complete lifetime boundary for a macOS native worker subtree
We are assessing a native macOS worker supervised by an independently protected background service. Our current Mac's system-version file reports macOS 27.0.1 (26A434), and the installed SDK declares es_new_descendants_client for macOS 27. No Endpoint Security client or experimental confinement has been activated. We need a supported public way to stop a job and verify that its controlled execution has ceased, even if workers fork, exec, call setsid/setpgid, are reparented, or their immediate supervisor crashes. Admission must remain closed until reconciliation after a failure. Delegation to outside services must either be denied or have its own enforceable ownership and stop contract. Does Apple provide a public API/configuration that establishes this hereditary ownership and complete termination boundary? In particular, does a descendants ES client's scope retain processes across parent exit/reparenting, and what supported operation can quiesce/terminate that entire owned population without a fork-versus-enumeration race? What remains enforced if that client dies or is deleted? We understand that fail-closed AUTH deadlines and es_sync_client alone do not establish this property. Please identify the supported interface, OS versions, entitlement/privilege requirements, relevant failure semantics and independently observable completion condition, or confirm the limits of this proposed combination. We are asking about the public contract, not private implementation details or a guarantee during kernel failure.
1
0
131
3d
launchd residual-process-group cleanup after main-job death: supported signals and timing
For current macOS 27, I am trying to establish the supported behavior of residual process-group cleanup before selecting an architecture. Consider a per-user launchd job whose actual main process O directly creates one fixed child F. F remains in the job's process group, creates no descendants, and does not change its process group or session. AbandonProcessGroup is not enabled. O may exit normally, crash, or receive SIGKILL while F remains alive. This is a documentary question; I am not presenting runtime observations or a reproducer. The installed launchd.plist(5) manual (dated 30 July 2019) describes cleanup of remaining same-process-group members when a job dies. It describes ExitTimeOut in terms of stopping a job. Historical Apple source contains a SIGTERM attempt in job_reap, but I do not assume that code describes current macOS behavior: https://github.com/apple-oss-distributions/launchd/blob/49a9c79b2949192dfca697b1054245cdfb645788/src/core.c What signals and escalation, if any, are supported for F after O has already died? Does the answer differ for normal exit, crash, or SIGKILL, or by per-user job domain? Does ExitTimeOut apply to that residual group after O is dead, or only to stopping the main job process? Is there a supported finite upper bound from O permanently ceasing execution to F being unable to execute further, including stopped or blocked F and O dying during child creation? If so, what is its documented timing origin and treatment of system sleep? If there is no supported bound, that clarification is sufficient. I have read the DTS answer about job runtime and CPU-versus-wall-time limits: https://developer.apple.com/forums/thread/845944 My question concerns residual-group cleanup after the actual main job process dies, rather than a separate requester's disappearance or the runtime limit of a still-live job.
1
0
75
1w
macOS: supported process-tree lifetime boundary after supervisor loss
I am building Ouroboros (ouro-jail), a contained developer workload runner. Before advertising native macOS support, I need a supported lifetime boundary that covers ordinary fork/spawn/exec descendants, including detached sessions and double-fork daemons. Execution must stay contained when every userspace custodian dies, rather than relying on a surviving process to enumerate and kill descendants. Does macOS provide a supported facility that can: Establish an immutable workload scope before its first instruction and atomically inherit membership through fork/spawn/exec, without modifying the workload or preventing ordinary Node, shell and Git subprocess behavior? Stop or terminate every member after loss of the final control owner, with enforcement retained in the kernel and no userspace callback required? Handle concurrent creation during teardown and expose a verifiable final drain, using stable process identities rather than PID-only scans? Development evidence on macOS 27.0 build 26A428, XNU 13432.1.9 (isolated VM, SIP already disabled in the guest; this is development evidence, not normal-SIP qualification): Descendant-scoped Endpoint Security clients observe the tested subtree. Reciprocal custodians handle either client's loss, but killing both leaves all known members running. Uncached fail-closed AUTH_EXEC lets a survivor execute a new command after both clients disappear (200 reciprocal-custody trials). PT_ATTACHEXC gives kernel-enforced debugger-death cleanup for attached targets, but later fork/spawn children survive (80 debugger-lifetime trials). A locally installed, identity-protected Mach exception handler is inherited through the tested fork/spawn/exec paths. Owner death changes it to a dead handler without stopping normal execution; a child can clear it. Breakpoint controls confirm real kernel exception delivery (24 Mach-lifetime trials). Published XNU contains per-task fatal-port no-senders cleanup, but machdep.task_get_fatal_port is absent on this tested release kernel. I have not treated it as a supported application API. LaunchServices creates a real application coalition, and XPC service lifetime follows app death. However, all seven workload descendants survive, retain coalition membership and can execute a new command. Shared and private audit sessions both fail; eight-second follow-ups also retain all seven survivors. A temporary root launchd service restarts and reaps seven recorded processes after a crash, but does not restart a stopped custodian (native-service trials). I understand Endpoint Security entitlement is separate from a lifetime guarantee. Please clarify whether an approved descendant-scoped ES deployment can provide that owner-loss guarantee through a documented API, whether another supported facility is appropriate, or whether meeting this contract requires a VM boundary. Below are the relevant parts of a focused C command-line reproduction (192 lines total, Xcode 27.0, SDK 27.0, -Wall -Wextra -Werror, no signing or third-party libraries). The code ran in the isolated VM; the packaged Xcode project has only been build-checked. 1. The owner installs a protected exception handler on itself, then forks the workload. No cleanup callback follows. static const exception_mask_t masks = EXC_MASK_SYSCALL | EXC_MASK_MACH_SYSCALL | EXC_MASK_BREAKPOINT; static const exception_behavior_t behavior = EXCEPTION_IDENTITY_PROTECTED | MACH_EXCEPTION_CODES; mach_port_t channel = MACH_PORT_NULL; mach_port_options_t options = {.flags = MPO_EXCEPTION_PORT | MPO_INSERT_SEND_RIGHT}; kern_return_t rc = mach_port_construct(mach_task_self(), &options, 0, &channel); if (rc != KERN_SUCCESS) return 4; rc = task_set_exception_ports(mach_task_self(), masks, channel, behavior, THREAD_STATE_NONE); if (rc != KERN_SUCCESS) return 4; pid_t child = fork(); if (!child) { /* Ordinary receive rights are not inherited. Only the kernel's task * exception-handler state provides supervision of this child. */ _exit(payload(directory, mode, exe)); } 2. The workload detaches (double-fork shown; fork, setsid and posix_spawn SETPGROUP/SETSID also tested; a child can also clear the handler with task_set_exception_ports(..., MACH_PORT_NULL, ...)). child = fork(); if (!child) { if (strcmp(mode, "fork") && setsid() < 0) _exit(4); if (!strcmp(mode, "double-fork")) { pid_t second = fork(); if (second < 0) _exit(4); if (second) _exit(0); } child_work(directory, mode); } 3. Each member reads its inherited handler state and keeps running ordinary BSD syscalls and a Mach trap. kern_return_t rc = task_get_exception_ports(mach_task_self(), masks, observed, &count, ports, behaviors, flavors); /* port == MACH_PORT_DEAD -> dead_mask, valid send right -> live_mask */ for (;;) { if (write(fd, ".", 1) != 1) _exit(3); /* heartbeat file */ (void)getpid(); mach_port_t thread = mach_thread_self(); mach_port_deallocate(mach_task_self(), thread); usleep(10000); } Observed output (double-fork case, original VM run). Workload, before and after SIGKILL of the owner (pid 1472): {"kind":"exception_state","role":"root","phase":"before_owner_loss","rc":0,"live_mask":448,"dead_mask":0} {"kind":"exception_state","role":"late-child","phase":"before_owner_loss","rc":0,"live_mask":448,"dead_mask":0} {"kind":"exception_state","role":"root","phase":"after_owner_loss","rc":0,"live_mask":0,"dead_mask":448} {"kind":"exception_state","role":"late-child","phase":"after_owner_loss","rc":0,"live_mask":0,"dead_mask":448} After owner loss, both root (pid 1473) and the detached late-child (pid 1475, own session) were still alive under the same uniqueid/pidversion, reparented to launchd, with heartbeat files still growing. Across 21 owner-death trials in 7 modes, 39 known fixture processes survived and no case left the fixture empty. The 3 breakpoint controls (owner alive) confirmed real exception delivery. Expected contract: a documented kernel-owned boundary prevents continued execution by every inherited member after all control owners disappear, without enumerating descendants after the fact or requiring workload cooperation. I am asking which supported macOS API meets that contract, not asserting that exception ports promise it. Apple DTS asked me to start this thread (Case-ID: 22799543) and will review once I reply with the link. The full reproduction steps and environment details are in the attached text. forum-attachment-reproduction.txt
3
0
445
1w
macOS: Reliable custody of a sandboxed worker if its controller dies during spawn
Hello, I'm investigating the supported macOS mechanisms for supervising a single unprivileged, sandboxed worker process. The target environment is macOS 15.6 (24G84), Apple Silicon (arm64). The worker is intended to operate under a separate Standard user identity, with tightly restricted capabilities and no requirement to create child processes. The main challenge is the startup failure window: A controller initiates worker creation, but exits unexpectedly before spawn returns or before the worker's identity and authenticated handshake can be independently recorded. In this situation, we need a supported approach to prevent the worker from becoming an unaccounted-for process, or to recover sufficiently trustworthy custody to determine its lifecycle and cleanup state. I have reviewed direct child-process supervision, POSIX process groups, launchd job behaviour, sandbox inheritance, resource limits and process identification mechanisms. I would appreciate guidance on the following: Is there a public, supported macOS API or system service that provides recoverable process custody from initial worker creation, including controller failure during startup? Could an application-associated XPC service or launchd mechanism provide the required lifecycle relationship without granting the worker independent ongoing execution authority? Is generation-safe, audit-token-based process signaling available through a supported public interface, and what are its privilege and acquisition requirements? Is setting a hard RLIMIT_NPROC limit before worker operations a supported way to prevent further fork/spawn activity by an unprivileged worker? What limitations or exceptions should be considered? What can macOS guarantee about process termination and cleanup after controller failure, and what must remain application-level verification? I'm particularly interested in documented guarantees and supported APIs rather than behaviour observed only in tests or private interfaces. Any recommendations or references to Apple documentation would be greatly appreciated. Thank you.
5
0
245
1w
Supported receiver-confinement guarantee for anonymous XPC connections on macOS 27.0.1
I’m assessing whether the public C XPC APIs provide the recipient guarantee needed for a local security boundary. The proposed path uses a dedicated anonymous listener, a transferred xpc_endpoint_t, and xpc_connection_create_from_endpoint. Before releasing protected data, I need to establish which process occurrence can receive it and whether that binding continues to hold through delivery. Here, “process occurrence” means one running instance, including protection against confusing it with a later instance that reuses its PID. The target reports macOS 27.0.1 (26A434), Darwin 27.0.0, arm64, and xnu-13432.1.9~1/RELEASE_ARM64_T6000. The selected Command Line Tools SDK reports macOS 27.0, SDK build 26A425. These are read-only inventory results; I have not run an XPC prototype for this question. Is there a supported public API contract that lets the sending application, or a separately authorized local verifier, establish before protected data becomes accessible that this connection’s actual receiver is the authenticated process occurrence and remains confined to it for that send? I specifically need to understand whether that guarantee covers endpoint copying or forwarding, repeated or concurrent connections created from one endpoint, process replacement, queued messages, and replies or access-capable attachments. I am asking about the selected C connection API; I do not assume equivalent behavior across the C and Swift session APIs. If a supported mechanism exists, which APIs, OS versions, privileges or entitlements are required, and where is the guarantee documented? If the public API does not expose this guarantee, a clear statement of that limit would help me choose an appropriate transport boundary. The distinction I need to resolve is between authenticating a peer at one point and ensuring that protected outgoing data reaches only that same process occurrence. I am seeking the supported security contract, without requesting access to private implementation details.
3
0
149
1w
How to distinguish a foreground cold launch from a background task cold launch?
I'm trying to determine why my UIKit application was launched, specifically whether it was launched by the user or by the system to execute a background task. I recently added a BGProcessingTask to update data overnight. Consider this scenario: The user backgrounds the app at 10 AM. A background task is scheduled with earliestBeginDate set to 4 AM the following day. During those 18 hours, iOS terminates the app's process to reclaim memory. iOS later decides to execute the scheduled background task and launches a new app process in the background. My understanding is that this results in a cold launch, including a call to application(_:didFinishLaunchingWithOptions:) and the initialization performed there. This matters because some of our startup initialization triggers network requests that are unnecessary when the app is launched only to perform a background task. Questions 1. Can iOS relaunch a previously terminated app to execute a scheduled BGProcessingTask? I'm referring specifically to termination by the system (for example, memory pressure), not the user force-quitting the application. 2. Is there a reliable way to distinguish a foreground cold launch from a background task cold launch inside application(_:didFinishLaunchingWithOptions:)? I tried checking UIApplication.shared.applicationState, but in my testing it was .background during didFinishLaunchingWithOptions in both scenarios, including when the user launched the app by tapping its icon. Is there another documented API or launch context that reliably identifies why the process was started? I'm aware that iOS provides launch options for certain launch scenarios, but I'm specifically interested in distinguishing a background task-triggered cold launch from a user-initiated foreground cold launch. 3. If this distinction cannot be made reliably during didFinishLaunchingWithOptions, what is the earliest lifecycle callback where I can determine that the app is entering the foreground? For example, should foreground-specific initialization be deferred until scene(_:willConnectTo:options:), sceneWillEnterForeground(_:), or another callback? I'm specifically looking for a documented and reliable lifecycle signal, rather than heuristics or arbitrary delays. The goal is to avoid unnecessary startup initialization and network requests when iOS launches the application solely to execute a background task.
2
0
237
2w
Subprocess ownership and timeout recovery on Intel macOS Monterey
Hi Quinn, Following your recommendation by email, I’m posting this as a new thread. Thank you again for your guidance on Virtualization.framework. This is a separate question about ordinary host-side subprocess ownership and timeout recovery, not VM cleanup. Target environment: Intel x86_64 macOS Monterey 12.7.6, build 21H1320 Python 3.13.15 Public, supported mechanisms; no root privileges, private APIs or kernel extensions We are verifying a subprocess supervision component with this process structure: Trusted caller process → runner → pytest → private helper → native subprocess Each parent normally owns the consuming wait for its direct child. The private helper exclusively manages signalling and reaping of its native child. Outer processes do not signal saved helper/native PIDs. Cancellation is cooperative, through channels and file/token delivery. The runner observes its fresh pytest child, drains stdout/stderr with bounded retention, and consumes its exact child’s status after exit is observed. The runner, pytest and helper are launched in separate sessions. Consequently, signalling pytest’s process group would not cover the separately sessioned helper and its native child. The unresolved failure case is: A fresh pytest invocation starts. Cancellation delivery fails, or delivery succeeds but the work does not finish. The runner continues observation and bounded output draining within the remaining deadline. The deadline expires while pytest or processes below it may still be alive. The runner reports an unresolved outcome and may exit. The caller also has a bounded deadline and may return without consuming its runner child. Closing capture pipes can cause EPIPE and disturb the child’s cleanup. Exiting a consuming parent also relinquishes its ability to collect that child’s eventual status. The outer caller does not automatically acquire wait rights over pytest or its descendants. Our current policy retains affected files, preserves the original failure, and prevents subsequent tests from starting. We do not treat cancellation delivery, pipe EOF, successful signal delivery, or direct-child reap as proof that every descendant has stopped. This prevents false success, but does not resolve responsibility for work that remains alive. We have considered separating the caller’s response lifetime from the consuming owners’ lifetimes: the caller could return an unresolved response while both existing parents remain alive, draining output and collecting their direct children later. However, keeping them alive adds no termination authority and does not address a crash of either owner. I am not asking for an absolute guarantee against arbitrary kernel failures, or a promise that SIGKILL always completes within a fixed time. I would like to understand the supported architectural approach on Monterey. My questions are: Is retaining the existing consuming parents beyond the response deadline the appropriate pattern, or is there a supported macOS facility that provides a better ownership and recovery boundary? What safe termination authority should those owners retain over their fresh direct children? If process groups are part of the solution, what lifecycle rules are needed to avoid acting on a reused identifier, particularly after leader exit or reaping? Is there a supported way to manage the separately sessioned helper/native work if an intermediate parent exits? Or must each level independently retain its own supervision and cleanup responsibility? If the consuming owner itself crashes, is there a supported recovery mechanism for ordinary subprocesses? Would launchd or XPC materially help, and what limitations would remain for descendants in separate sessions? Which design constraint would you recommend changing: cooperative-only cancellation, the fixed lifetime of the runner, or the process topology? These are our current choices, not restrictions we assume macOS imposes. Our practical goal is a bounded response while an identifiable owner remains responsible for unsettled work, with appropriate termination authority and an honest unresolved outcome when cleanup cannot be established. The immediate qualification scope is only three simple tests, using shell bodies such as exit, kill -9 $$, and echo with ordinary exit statuses. They contain no intentional background work, pipelines or command substitutions. We would prefer a proportionate supported pattern rather than a new general supervision framework. If a reduced example would help clarify the question, I can provide one. Thank you for your time and guidance.
6
0
161
2w
Diagnosing pre-main latency in a short-lived macOS child process while preserving its parent
I’m looking for a supported way to investigate startup latency before main() in a short-lived native macOS child process, while preserving its original parent-child relationship. Environment macOS 26.6.2, build 25G83. Native arm64 executables. The on-disk /usr/lib/dyld contains the identifier dyld-1387; this is a static observation, not independent verification of all runtime shared-cache components. The diagnostic runs were started manually from normal macOS Terminal. All inputs and target processes are synthetic test fixtures. Execution structure Test supervisor → Watchdog → Observer → Query Observer launches Query using posix_spawn(). Query checks a synthetic target process’s identity using Security.framework and produces a fixed 28-byte result. Observer passes an explicit environment containing only LANG=C and LC_ALL=C. Consequently, exporting DYLD variables in the outer Terminal would not pass them to Query. Our existing test has a 1000 ms Query deadline and requires empty Query stderr. This is an application-defined acceptance requirement, not a claimed macOS timing guarantee. Observed results A historical full regression run timed out at approximately 1001 ms, with no Query result bytes received. That run did not have main-entry instrumentation, so we cannot determine where its time was spent. A later isolated, instrumented run measured: posix_spawn return to Query main entry: 832.687 ms main entry to return: 24.179 ms Observer-measured Query elapsed time: 864 ms Another isolated, instrumented run measured: posix_spawn call duration: 0.179 ms spawn return to main entry: 634.334 ms main entry to return: 6.757 ms Observer-measured Query elapsed time: 647 ms In the third run, getrusage(RUSAGE_SELF) at main entry reported cumulative CPU time of 3.014 ms user and 2.583 ms system. Before main returned, the cumulative total was 8.088 ms. Timeline measurements used CLOCK_MONOTONIC. Interpretation limits These successful diagnostic runs do not explain or resolve the historical timeout. Instrumentation changes the executable, and cache state and scheduling may differ. The CPU and wall-clock measurements cover different intervals. Subtracting them would not give an exact waiting-time measurement. We cannot currently attribute the delay to dyld, scheduling, security checks, IPC, or I/O. Diagnostic constraints We want to preserve the original parent-child relationship and avoid system-wide collection, disabling security protections, or silently changing permissions. We have not established that the Instruments App Launch configuration available to us can capture this child’s earliest startup phases while restricting collection to Query. The historical DYLD_PRINT_STATISTICS options are not documented in the installed dyld manual. Attaching a sampling tool after obtaining the PID may miss the relevant startup interval and may perturb this short-lived process. Questions What supported tool or API on this macOS version can distinguish startup phases before main() for this posix_spawn-created child? Can collection itself be restricted to Query, rather than collecting system-wide data and filtering the report afterward? What permissions are required, which early phases remain unobservable, and how much observer perturbation should we expect? If these constraints cannot all be met, what is the smallest necessary change to the diagnostic setup? What minimal sample project and evidence would be most useful for further investigation? I have preserved the original failure and subsequent diagnostic evidence, but do not yet have a standalone Xcode sample that reliably reproduces the historical timeout. I’m requesting guidance on an appropriate measurement method, not asserting that this is a confirmed macOS defect.
4
0
150
2w
macOS XPC: Can incoming message size be bounded before payload allocation?
Hello, I'm designing a local macOS helper service (minimum deployment target: macOS 13) that performs one fixed syntax-validation operation. The submitted source is never executed. The security contract requires: A maximum incoming transport request size of 327,680 bytes. Immediate rejection when the 327,681st byte is encountered, without an allocation proportional to an unbounded sender-controlled payload. No application-level response for an oversized transport request, followed by termination of the affected connection. Complete application responses limited to 65,536 bytes, without treating truncated output as successful. I've reviewed the public XPC APIs, including xpc_data_get_length, xpc_connection_cancel, and xpc_connection_set_peer_code_signing_requirement. The remaining uncertainty is whether XPC can enforce a receiver-side message-size limit before materializing the incoming payload. My questions are: Does any public XPC API on macOS 13+ provide a documented maximum incoming message size that is enforced before payload materialization or proportional allocation? If not, is the entire incoming XPC message necessarily materialized before the application event handler receives it? Is there a supported XPC design for guaranteeing bounded receiver memory with untrusted input, or should this requirement use a different local transport, such as an AF_UNIX SOCK_STREAM socket? What guarantees does xpc_connection_cancel provide regarding connection termination, pending messages, and prevention of connection reuse after detecting malformed or oversized input? I'm specifically looking for documented platform guarantees rather than behavior that happens to work in testing. Thank you!
4
0
278
2w
Supported libSystem state after a LaunchDaemon permanently drops privileges
I am testing a fixed signed LaunchDaemon startup program that uses setgroups, setgid and setuid to establish a dedicated non-root identity before loading its service library or creating an application XPC listener. This follows the single-process, deferred-library direction discussed in DTS thread 844906. The remaining question is the supported treatment of system-runtime state initialized before the credential transition. Test environment: Apple silicon, macOS 27.0.1 / Darwin 27.0.0, hardened runtime, no special entitlements. The host links only libSystem and has no application constructors. This is a temporary diagnostic, not an installed product or a file-operation service. Our test verifies real, effective and saved UID/GID, the exact supplementary group vector and failed attempts to regain root. After the transition, a read-only own-task Mach inventory still sees a voucher even though successful task/current-thread voucher getters return null. It also sees one send+receive endpoint without an alias to any of the queried special/registered roles. Ordinary hardened launchd controls in both the login GUI and user domains also have a voucher and such an endpoint. Their recorded endpoint attributes match the post-drop test: empty queue, sequence 1, make-send count 1, send rights present, no send-once rights, port sets or notification requests. We do not treat this as proof that the objects or authority are equivalent. No messages are sent to the unidentified endpoint and no runtime-owned rights are destroyed. In a separate ordinary-user test, public voucher recipe extraction reports only a BANK attribute. Published libdispatch source describes a default task-bank voucher stored separately from the current thread's voucher slot. Published XNU source captures identity when bank context is initialized. We have not established the corresponding lifecycle or authority implications on this OS release, and do not claim that the observed voucher retains root authority. For this startup arrangement, what supported public contract should an application use to establish that libSystem's retained runtime context does not preserve usable pre-drop administrator authority before loading service code? Is there a supported sanitization step, or a specific documented OS trust assumption under which leaving that state intact is intended? If the combination of exact group reduction, deferred service loading and launchd Mach-service check-in cannot support that boundary, which public architecture should we use instead? We are seeking a documented arrangement or a clear limit on the guarantee, rather than a private reset API or an explanation of every internal endpoint. We have not used same-PID exec, a root supervisor, private APIs, or a broad port-type allowlist. Relevant documentation or a minimal public sample would help.
1
0
304
2w
macOS 14+: Safely supervising worker-created child processes.
Hello Apple Developer Community, We are developing a macOS application with a minimum deployment target of macOS 14.0. We are investigating a process-supervision safety problem involving the following topology: Root → Worker → Child The Worker creates the Child using native process APIs and is responsible for supervising its lifecycle. The critical failure scenario Worker successfully creates Child. Child exists, but its verified process identity has not yet been communicated to Root. Worker unexpectedly terminates before completing the identity handoff. Root must avoid signaling an unrelated process while ensuring that an untracked Child cannot continue executing without authorization. Our safety requirements Independently establish Child's exact process-lifetime identity. Prevent unsafe process signaling caused by PID reuse. Handle Worker failure before identity handoff. Verify process termination and disposition. Avoid relying on private APIs or restricted entitlements. Maintain compatibility with macOS 14 and later. What we have investigated We have reviewed posix_spawn, waitpid, process observation APIs, audit-token-based process identification and signaling, Endpoint Security, and launchd-based supervision. We understand that Endpoint Security FORK events are notifications rather than authorization events, and that dropped notifications may prevent complete birth tracking. We also found es_new_descendants_client in the macOS 27 SDK, but it requires an Endpoint Security entitlement and does not meet our current macOS 14 deployment requirements. We understand that a process cannot automatically use waitpid to reap a grandchild merely because the intermediate parent has terminated. Our questions Is there a publicly supported macOS 14+ API or process-supervision mechanism that can reliably establish the identity of a Worker-created Child even if Worker terminates before communicating that identity? Is there a supported approach for safely containing such a Child when its identity is not yet known to Root? Can audit-token-based signaling provide sufficient process-lifetime identity guarantees for this scenario, and what minimum macOS version supports the relevant APIs? Is there a supported mechanism for independently verifying Child termination when Root is not its direct parent? If this cannot be guaranteed using public APIs, would Apple recommend changing the architecture so that Root directly creates and supervises Child? We are not requesting private API access or Endpoint Security entitlements. We would appreciate guidance on the supported macOS process-lifecycle contracts before proceeding with implementation. Thank you for your assistance.
5
0
565
2w
C-XPC on macOS 14: Do connection EUID/ASID and message-derived SecCode identify the same sender?
Platform / environment Minimum deployment target: macOS 14.0. Development environment: macOS 26.3, Xcode 26.6, macOS SDK 26.5, Swift 6.3.3. We are evaluating public C-XPC and Security.framework APIs; we have not yet validated this identity model over a real C-XPC connection. Context A per-user, signed Runtime Host accepts a connection from a separately signed client. Let peer be the accepted C-XPC peer connection, and receivedMessage the original request dictionary delivered by that connection's event handler. Our admission policy requires both (a) the effective UID and audit session of the actual message sender and (b) validation of that sender's dynamic code against an independently configured code-signing requirement. No application-level authority is granted before these checks. API sequence under review We would first read xpc_connection_get_euid(peer) and xpc_connection_get_asid(peer), then obtain a dynamic code reference via SecCodeCreateWithXPCMessage(receivedMessage, kSecCSDefaultFlags, &code). We would validate that reference with SecCodeCheckValidity(code, kSecCSDefaultFlags, approvedRequirement), where approvedRequirement is configured independently of the peer, and finally inspect the required signing information with SecCodeCopySigningInformation. Reading signing information is not a substitute for code validation. Question On macOS 14, is there a documented, supported guarantee that the connection-level EUID/ASID and the message-derived SecCode refer to the same process occurrence and the actual sender of this particular received request? The connection getters describe attributes captured when the connection was established, while SecCodeCreateWithXPCMessage derives a dynamic-code reference from the original received XPC dictionary. We do not assume that these APIs provide an atomic identity snapshot or prove that their observations refer to the same sender process instance. In particular, what are the limits of any such guarantee when messages or messaging capabilities are forwarded, a process calls exec, a process exits or is replaced, credentials or audit sessions change, or a connection is interrupted and re-established? What if the sender's state changes between message reception and completion of the validation sequence? Request for a supported alternative If this API sequence does not establish that correspondence, which public APIs available on macOS 14 can provide the effective UID, audit session ID, and dynamic-code identity from the same received-message provenance? We are not considering PID-only lookup, private audit-token access, or caller-supplied identity claims. A clarification that the requested guarantee is unavailable would also be valuable. References xpc_connection_get_euid xpc_connection_get_asid Apple DTS: Validating Signature Of XPC Process
0
0
107
3w
Supported completeness and lifecycle guarantees for es_new_descendants_client
Hello Apple Developer Technical Support, I am evaluating es_new_descendants_client for a local command runner that must report success only after its workload and every process descended from that workload have exited. If observation is incomplete or ambiguous, the runner must report failure. This is a design inquiry, not a report of a reproduced operating-system defect; no entitled prototype has been tested. The proposed observer would create its client and subscribe to lifecycle notifications before launching any workload. It would maintain a registry using process-lifetime identities, add processes on creation and remove them on exit. An unmatched event, missing required field, detected loss or observer failure would invalidate the run. It would consider closure only after all registered workload processes had exited. We have not established that these rules are sufficient. Could you clarify which of the following properties are supported API guarantees, and identify any that applications must not rely on? A documented reference or an explicit statement that a guarantee is unavailable would both help. Please identify applicable macOS/SDK versions and any known version-dependent limitations. 1. Membership and creation-event coverage Does the observed subtree retain a process and all of its future descendants after its original parent exits, it is reparented, it double-forks, or it changes process group/session with setpgid or setsid? Could a process remain observable for exit while creation events for its children become invisible? For a workload launched after successful subscription, does every successful process-creation path—including fork, vfork and posix_spawn—produce a lifecycle event sufficient to register the new process before closure can be declared? Which event and identity fields should be used for each path, including a child that exits without a successful exec? Does the calling observer receive the necessary event for its own initial workload launch? 2. Ordering and the meaning of exit Is there a supported per-client ordering guarantee that every child-creation event from a process is delivered before that process's exit notification, including concurrent creation and exit? Can the child's events arrive before the event that introduces that child? Please distinguish kernel enqueue order, handler delivery order and any processing order the application must impose. At what lifecycle boundary is ES_EVENT_TYPE_NOTIFY_EXIT generated? Does it establish that the identified process can no longer execute or initiate writes, or can relevant activity continue after the notification? We would not equate process exit with filesystem durability or completion of work already delegated to other processes. 3. Muting and other visibility filters Does a newly created descendants client have default process, path or target-path mutes that can suppress fork/exit notifications? What supported sequence of configuration and inspection calls establishes complete lifecycle visibility before launch, including mute inversion and executable-path changes? Apart from subscription and muting, are there policy, security, rate-limit or client-type exclusions that can suppress those events? Which suppressed events, if any, are intentionally absent from the sequence counter rather than reported as drops? 4. Sequence numbers and loss detection The global_seq_num documentation requires message version greater than 4. Is that field guaranteed for descendants-client lifecycle messages? Do notifications concerning the calling observer and its descendants use the same per-client sequence? How can a client establish a valid initial baseline and detect loss before its first received message? Is every dropped subscribed, unmuted lifecycle event reflected in the next delivered sequence number? What counter reset, wraparound or client-recreation rules must be handled? Would the proposed registry rule make terminal loss fail safely—for example, a lost final exit leaves a process registered—under the supported ordering and visibility semantics? Or is there a counterexample in which the registry can become empty while an unobserved descendant survives? 5. Synchronization, observer failure and delegated work Does es_sync_client provide any loss/completeness information beyond draining preceding queued messages? Its documented callbacks also run for a destroyed or null client, so we would not interpret callback arrival alone as successful completion. Is there a supported mechanism to distinguish a healthy drain from invalidation? What does “instigates” cover for this client? In particular, can it observe or attribute work executed by existing launchd/XPC services, or by unrelated processes receiving file descriptors? We would treat such work as outside a lineage-only closure claim unless it is explicitly covered or independently excluded. Does this client provide any supported protection against a same-UID workload stopping, killing or otherwise interfering with its observer, or must that isolation be supplied separately? Observer failure would invalidate the run; we are not assuming ES supplies a write barrier for evidence files. 6. Supported cleanup and deployment Is there a supported public mechanism to signal a non-child descendant by process-lifetime identity, without a PID-reuse race between observing it and sending a signal? Is there a recommended approach if the observer cannot wait on that process? We do not want to depend on private libproc functions as an application contract. Finally, is this use case eligible for com.apple.developer.endpoint-security.client in a standalone signed command-line observer, and what supported signing/provisioning or packaging requirements apply? This is a request for guidance, not an entitlement application. Our central question is whether supported APIs can establish complete descendant-process closure under these constraints. If they cannot, we would appreciate a clear statement of that limitation or a supported alternative. Thank you. Documentation consulted: es_new_descendants_client es_sync_client global_seq_num es_process_t
6
0
882
3w
Processes & Concurrency Resources
General: DevForums subtopic: App & System Services > Processes & Concurrency Processes & concurrency covers a number of different technologies: Background Tasks Resources Concurrency Resources — This includes Swift concurrency. Service Management Resources XPC Resources Share and Enjoy — Quinn “The Eskimo!” @ Developer Technical Support @ Apple let myEmail = "eskimo" + "1" + "@" + "apple.com"
Replies
0
Boosts
0
Views
1.7k
Activity
Jul ’25
ExitTimeOut appears to be capped at 60 seconds, and ExitTimeOut 0 kills immediately
On macOS 27.x (Apple silicon) I've been measuring how launchd stops a job, and two behaviors don't match the documentation. Method: a throwaway job whose script traps SIGTERM and logs it, bootstrapped with different ExitTimeOut values, then stopped with launchctl bootout while timing when the process dies. Observed (LaunchAgent in the gui domain; the same results in the system domain with a LaunchDaemon): ExitTimeOut 45 -> `launchctl print` reports 45; SIGTERM, then SIGKILL at 45 s ExitTimeOut 61 -> reports 60; SIGTERM, then SIGKILL at 60 s ExitTimeOut 90 -> reports 60; SIGTERM, then SIGKILL at 60 s ExitTimeOut 120 -> reports 60; SIGTERM, then SIGKILL at 60 s ExitTimeOut 0 -> reports 0; SIGKILL after ~0.1 s, SIGTERM never deliveredman launchd.plist says of ExitTimeOut: "The amount of time launchd waits between sending the SIGTERM signal and before sending a SIGKILL signal when the job is to be stopped. The default value is system-defined. The value zero is interpreted as infinity and should not be used, as it can stall system shutdown forever." So: is there a 60-second ceiling on ExitTimeOut? It isn't documented that I can find, and it applies in both domains. And is zero meant to be "infinity" as documented, or an immediate SIGKILL as observed? Finally, is there a supported way for a service to be given more than 60 seconds to exit when launchd stops it — or is 60 seconds simply the maximum? Happy to file a Feedback with a minimal repro if that's useful.
Replies
2
Boosts
0
Views
149
Activity
16h
What happens after BGContinuedProcessingTask "expires"?
If I create a BGContinuedProcessingTaskRequest, register it, and then "do work" within it appropriately reporting progress, and before my task has finished doing all the work it had to do, its expirationHandler triggers... does the task later try again? Or does it lose the execution opportunity until the app is next re-launched to the foreground? In my testing, I never saw my task execute again once expired (which suggests the latter?). I was able to easily force this expiry by starting my task, backgrounding my app, then launching the iOS Camera App. My example is just using test code inspired from https://developer.apple.com/documentation/backgroundtasks/performing-long-running-tasks-on-ios-and-ipados let request = BGContinuedProcessingTaskRequest(identifier: taskIdentifier, title: "Video Upload", subtitle: "Starting Upload") request.strategy = .queue BGTaskScheduler.shared.register(forTaskWithIdentifier: taskIdentifier, using: nil) { task in guard let task = task as? BGContinuedProcessingTask else { return } print("i am a good task") var wasExpired = false task.expirationHandler = { wasExpired = true } let progress = task.progress progress.totalUnitCount = 100 while !progress.isFinished && !wasExpired { progress.completedUnitCount += 1 let formattedProgress = String(format: "%.2f", progress.fractionCompleted * 100) task.updateTitle(task.title, subtitle: "Completed \(formattedProgress)%") sleep(1) } if progress.isFinished { print ("i was a good task") task.setTaskCompleted(success: true) } else { print("i was not a good task") task.setTaskCompleted(success: false) } } try? BGTaskScheduler.shared.submit(request) Apologies if this is clearly stated somewhere and I'm missing it.
Replies
5
Boosts
0
Views
597
Activity
18h
SecCodeCreateWithXPCMessage: sender identity across concurrent receives, exec, and deferred replies
I am evaluating a local macOS C XPC design. The target under consideration is macOS 27.0.1, build 26A434, on Apple silicon. This is a source-design question; I have not run a reproducer or established that the public source below matches that OS build. The public SecCode.h comment describes SecCodeCreateWithXPCMessage as obtaining a code reference for the sender of the supplied XPC message using associated audit identity. The implementation at Apple Security commit 97c3a4296c1ea06b0fe1877a7e616aa84450b5b2 obtains the dictionary's remote connection, takes that connection's audit token, and uses it for code lookup: https://github.com/apple-oss-distributions/Security/blob/97c3a4296c1ea06b0fe1877a7e616aa84450b5b2/OSX/libsecurity_codesigning/lib/SecCode.h https://github.com/apple-oss-distributions/Security/blob/97c3a4296c1ea06b0fe1877a7e616aa84450b5b2/OSX/libsecurity_codesigning/lib/SecCode.cpp Function anchor in both files: SecCodeCreateWithXPCMessage. I am treating this as a question about the supported API contract, not evidence of a vulnerability or proof of installed implementation. For an actual received C XPC dictionary M, retained for deferred processing, I need to understand the supported identity and reply guarantees: Does SecCodeCreateWithXPCMessage(M, ...) resolve audit identity fixed to M's original sender occurrence, or can the associated connection's identity at lookup time differ? In particular, what is guaranteed if another message arrives or processing occurs concurrently on another queue? If the sending process performs exec before the lookup, or after lookup but before a reply, what does the resulting SecCode reference identify? Is there a documented supported way to distinguish the original message-sending occurrence and executable from a later executable or replacement peer without using PID-based reconstruction or private XPC APIs? If I retain M and later use its supported C reply context, does the reply remain addressed to that same original sending occurrence? What are the documented effects of connection invalidation, exec, forwarding/delegation of relevant rights and outstanding aliases? I am not assuming that retaining M or the returned SecCode reference locks peer identity or revokes other holders. If these APIs do not jointly provide those guarantees, which public API and ownership pattern should a design use to validate the actual eventual reply recipient before sending sensitive data? A statement that a guarantee is unavailable or requires a different design would also help. Please distinguish C XPC behavior from Swift XPCReceivedMessage; I am not assuming an undocumented conversion between them. Could you point to the applicable documentation and supported macOS versions, and clarify whether the cited public source revision is representative of the target? If exact-build behavior cannot be established publicly, please identify that limitation. This question concerns transport identity and context lifetime only. A valid code identity would still need separate application authorization; I am not asking XPC to issue role, run or resource authority. I would prefer a documented contract over an inference from a successful test. I can prepare a separately scoped minimal example if one is necessary, but no executable example is included in this question.
Replies
5
Boosts
0
Views
179
Activity
2d
Title: Supported OS-enforced restriction of Keychain access while retaining App Sandbox and App Group UDS
I’m designing a small, controlled macOS test harness. Two separately signed, sandboxed applications communicate through a UNIX-domain socket in an App Group container. They run as non-root processes in a GUI user session. One application also launches a child that inherits its sandbox and an existing socket descriptor. Is there a documented, supported OS policy that preserves this IPC arrangement while preventing the test processes from retrieving, using or modifying credentials, including items in their own Data Protection Keychain access groups and reachable file-based keychains? The policy must also prevent creating credential stores/items outside the permitted test resources. Using a macOS-style TeamID-prefixed App Group avoids that group providing Keychain sharing, but does not establish denial of the remaining Keychain operations. Empty stores, avoiding API calls and relying on users refusing prompts are insufficient for this requirement. If a different execution context or isolation architecture is required, could you identify the supported mechanism and relevant documentation? I’m seeking platform guidance, without relying on private APIs or unsupported custom sandbox profiles.
Replies
3
Boosts
0
Views
290
Activity
3d
Supported diagnosis for posix_spawn EPERM when launching a sandboxed local QA host
On macOS 15.7.9 (24G830), arm64, using Xcode 16.4 (16F6), a locally built QA host fails to launch through LaunchServices using open -W. The recorded signature is ad hoc, with no TeamIdentifier; its only recorded effective entitlement is com.apple.security.app-sandbox=true. The historical launch returned -10810. Correlated logs report posix_spawn: Operation not permitted (errno 1). Host entry was not observed. A packaging revision embedded the same Info.plist in __TEXT,__info_plist. Recorded signature verification succeeded, but the next launch produced the same rejection. The responsible policy remains unidentified; these observations are not an independently validated minimal reproducer. What supported diagnostic procedure can identify the policy responsible for this rejection without disabling security protections or using an alternative launch route?
Replies
1
Boosts
0
Views
113
Activity
3d
Keeping every descendant of a sandboxed XPC service’s worker inside its lifetime (fork, double-fork, setsid)
Apple DTS case 22893354: forum post and reply Apple asked for the question as a Developer Forums post, then a reply to the case email with the post URL. Nothing below has been posted or sent. 1. Forum post Post at https://developer.apple.com/forums/ (signed in, "Ask a question"). Suggested tags: XPC, App Sandbox, Endpoint Security Attach: fixtures/egress_guard/hp04/apple-descendant-sample/main.c, renamed to main.txt if the forum refuses .c. Title Keeping every descendant of a sandboxed XPC service's worker inside its lifetime (fork, double-fork, setsid) Body We are designing a macOS app that runs an unmodified third-party command-line tool for one task at a time. The plan is an app-bundled, sandboxed XPC service that launches the tool as a child process. The tool is not ours, so we have to assume it may fork without exec, double-fork, and call setsid(). For each run we need one guarantee: after the run ends, every process the tool created has stopped. "Ends" includes the XPC service crashing and the host app crashing, not only a clean cancel. If we cannot prove that, we cannot report the run as finished. What we have looked at so far: Killing the process group. A child that calls setsid() is no longer in the group. launchd's process-group cleanup for the job. As we read launchd.plist(5), that also covers the process group only. Tracking pids from fork and exit notifications, including Endpoint Security. Notifications can be dropped, and pids can be reused, so a list rebuilt from events is not proof that nothing is left. The attached sample shows the process shape without any sandbox or XPC. It starts a worker, the worker double-forks, and the grandchild calls setsid() and keeps writing to a log after the original process has exited. On macOS 15.6.1 the descendant shows parent pid 1 and its own session, and it keeps writing until it finishes on its own: // worker: fork twice, let the intermediate processes exit if (fork() > 0) _exit(0); if (fork() > 0) _exit(0); setsid(); // leaves the original process group and session for (int i = 0; i < 8; i++) { // append "tick i pid ppid" to the log, ppid is now 1 usleep(200000); }Build with cc -Wall -Wextra -Werror -o DescendantOutlivesParent main.c and run ./DescendantOutlivesParent /tmp/descendant-log /tmp/descendant-ready. Questions: Is there a supported mechanism that ties every descendant of a process started by an XPC service, including ones that called setsid(), to the lifetime of that service, so that they are terminated when the service exits or crashes? If the service is sandboxed, does sandbox inheritance (children inherit the parent's sandbox) also give us a way to find or terminate those descendants, or does it only restrict what they can do? If neither, what does Apple recommend for running an untrusted command-line tool where leftover descendants must be ruled out? For example, is a separate launchd job per run, a different process-management API, or Endpoint Security authorization the intended route? Can that mechanism be combined with per-run file access (one input folder and one scratch folder per run), without giving the tool a shared container or network access? We would rather learn that a guarantee is not available than build on an assumption, so a "this is not supported" answer is also useful to us. 2. Reply to the DTS email Reply to Apple's case email (keep the subject) after the post is live: Case-ID: 22893354 Hello, Thank you. I posted the question on the Developer Forums here: <FORUM POST URL> The sample project is attached to the post. There is nothing private in it. Best regards, <NAME>
Replies
1
Boosts
0
Views
67
Activity
3d
Supported complete lifetime boundary for a macOS native worker subtree
We are assessing a native macOS worker supervised by an independently protected background service. Our current Mac's system-version file reports macOS 27.0.1 (26A434), and the installed SDK declares es_new_descendants_client for macOS 27. No Endpoint Security client or experimental confinement has been activated. We need a supported public way to stop a job and verify that its controlled execution has ceased, even if workers fork, exec, call setsid/setpgid, are reparented, or their immediate supervisor crashes. Admission must remain closed until reconciliation after a failure. Delegation to outside services must either be denied or have its own enforceable ownership and stop contract. Does Apple provide a public API/configuration that establishes this hereditary ownership and complete termination boundary? In particular, does a descendants ES client's scope retain processes across parent exit/reparenting, and what supported operation can quiesce/terminate that entire owned population without a fork-versus-enumeration race? What remains enforced if that client dies or is deleted? We understand that fail-closed AUTH deadlines and es_sync_client alone do not establish this property. Please identify the supported interface, OS versions, entitlement/privilege requirements, relevant failure semantics and independently observable completion condition, or confirm the limits of this proposed combination. We are asking about the public contract, not private implementation details or a guarantee during kernel failure.
Replies
1
Boosts
0
Views
131
Activity
3d
launchd residual-process-group cleanup after main-job death: supported signals and timing
For current macOS 27, I am trying to establish the supported behavior of residual process-group cleanup before selecting an architecture. Consider a per-user launchd job whose actual main process O directly creates one fixed child F. F remains in the job's process group, creates no descendants, and does not change its process group or session. AbandonProcessGroup is not enabled. O may exit normally, crash, or receive SIGKILL while F remains alive. This is a documentary question; I am not presenting runtime observations or a reproducer. The installed launchd.plist(5) manual (dated 30 July 2019) describes cleanup of remaining same-process-group members when a job dies. It describes ExitTimeOut in terms of stopping a job. Historical Apple source contains a SIGTERM attempt in job_reap, but I do not assume that code describes current macOS behavior: https://github.com/apple-oss-distributions/launchd/blob/49a9c79b2949192dfca697b1054245cdfb645788/src/core.c What signals and escalation, if any, are supported for F after O has already died? Does the answer differ for normal exit, crash, or SIGKILL, or by per-user job domain? Does ExitTimeOut apply to that residual group after O is dead, or only to stopping the main job process? Is there a supported finite upper bound from O permanently ceasing execution to F being unable to execute further, including stopped or blocked F and O dying during child creation? If so, what is its documented timing origin and treatment of system sleep? If there is no supported bound, that clarification is sufficient. I have read the DTS answer about job runtime and CPU-versus-wall-time limits: https://developer.apple.com/forums/thread/845944 My question concerns residual-group cleanup after the actual main job process dies, rather than a separate requester's disappearance or the runtime limit of a still-live job.
Replies
1
Boosts
0
Views
75
Activity
1w
macOS: supported process-tree lifetime boundary after supervisor loss
I am building Ouroboros (ouro-jail), a contained developer workload runner. Before advertising native macOS support, I need a supported lifetime boundary that covers ordinary fork/spawn/exec descendants, including detached sessions and double-fork daemons. Execution must stay contained when every userspace custodian dies, rather than relying on a surviving process to enumerate and kill descendants. Does macOS provide a supported facility that can: Establish an immutable workload scope before its first instruction and atomically inherit membership through fork/spawn/exec, without modifying the workload or preventing ordinary Node, shell and Git subprocess behavior? Stop or terminate every member after loss of the final control owner, with enforcement retained in the kernel and no userspace callback required? Handle concurrent creation during teardown and expose a verifiable final drain, using stable process identities rather than PID-only scans? Development evidence on macOS 27.0 build 26A428, XNU 13432.1.9 (isolated VM, SIP already disabled in the guest; this is development evidence, not normal-SIP qualification): Descendant-scoped Endpoint Security clients observe the tested subtree. Reciprocal custodians handle either client's loss, but killing both leaves all known members running. Uncached fail-closed AUTH_EXEC lets a survivor execute a new command after both clients disappear (200 reciprocal-custody trials). PT_ATTACHEXC gives kernel-enforced debugger-death cleanup for attached targets, but later fork/spawn children survive (80 debugger-lifetime trials). A locally installed, identity-protected Mach exception handler is inherited through the tested fork/spawn/exec paths. Owner death changes it to a dead handler without stopping normal execution; a child can clear it. Breakpoint controls confirm real kernel exception delivery (24 Mach-lifetime trials). Published XNU contains per-task fatal-port no-senders cleanup, but machdep.task_get_fatal_port is absent on this tested release kernel. I have not treated it as a supported application API. LaunchServices creates a real application coalition, and XPC service lifetime follows app death. However, all seven workload descendants survive, retain coalition membership and can execute a new command. Shared and private audit sessions both fail; eight-second follow-ups also retain all seven survivors. A temporary root launchd service restarts and reaps seven recorded processes after a crash, but does not restart a stopped custodian (native-service trials). I understand Endpoint Security entitlement is separate from a lifetime guarantee. Please clarify whether an approved descendant-scoped ES deployment can provide that owner-loss guarantee through a documented API, whether another supported facility is appropriate, or whether meeting this contract requires a VM boundary. Below are the relevant parts of a focused C command-line reproduction (192 lines total, Xcode 27.0, SDK 27.0, -Wall -Wextra -Werror, no signing or third-party libraries). The code ran in the isolated VM; the packaged Xcode project has only been build-checked. 1. The owner installs a protected exception handler on itself, then forks the workload. No cleanup callback follows. static const exception_mask_t masks = EXC_MASK_SYSCALL | EXC_MASK_MACH_SYSCALL | EXC_MASK_BREAKPOINT; static const exception_behavior_t behavior = EXCEPTION_IDENTITY_PROTECTED | MACH_EXCEPTION_CODES; mach_port_t channel = MACH_PORT_NULL; mach_port_options_t options = {.flags = MPO_EXCEPTION_PORT | MPO_INSERT_SEND_RIGHT}; kern_return_t rc = mach_port_construct(mach_task_self(), &options, 0, &channel); if (rc != KERN_SUCCESS) return 4; rc = task_set_exception_ports(mach_task_self(), masks, channel, behavior, THREAD_STATE_NONE); if (rc != KERN_SUCCESS) return 4; pid_t child = fork(); if (!child) { /* Ordinary receive rights are not inherited. Only the kernel's task * exception-handler state provides supervision of this child. */ _exit(payload(directory, mode, exe)); } 2. The workload detaches (double-fork shown; fork, setsid and posix_spawn SETPGROUP/SETSID also tested; a child can also clear the handler with task_set_exception_ports(..., MACH_PORT_NULL, ...)). child = fork(); if (!child) { if (strcmp(mode, "fork") && setsid() < 0) _exit(4); if (!strcmp(mode, "double-fork")) { pid_t second = fork(); if (second < 0) _exit(4); if (second) _exit(0); } child_work(directory, mode); } 3. Each member reads its inherited handler state and keeps running ordinary BSD syscalls and a Mach trap. kern_return_t rc = task_get_exception_ports(mach_task_self(), masks, observed, &count, ports, behaviors, flavors); /* port == MACH_PORT_DEAD -> dead_mask, valid send right -> live_mask */ for (;;) { if (write(fd, ".", 1) != 1) _exit(3); /* heartbeat file */ (void)getpid(); mach_port_t thread = mach_thread_self(); mach_port_deallocate(mach_task_self(), thread); usleep(10000); } Observed output (double-fork case, original VM run). Workload, before and after SIGKILL of the owner (pid 1472): {"kind":"exception_state","role":"root","phase":"before_owner_loss","rc":0,"live_mask":448,"dead_mask":0} {"kind":"exception_state","role":"late-child","phase":"before_owner_loss","rc":0,"live_mask":448,"dead_mask":0} {"kind":"exception_state","role":"root","phase":"after_owner_loss","rc":0,"live_mask":0,"dead_mask":448} {"kind":"exception_state","role":"late-child","phase":"after_owner_loss","rc":0,"live_mask":0,"dead_mask":448} After owner loss, both root (pid 1473) and the detached late-child (pid 1475, own session) were still alive under the same uniqueid/pidversion, reparented to launchd, with heartbeat files still growing. Across 21 owner-death trials in 7 modes, 39 known fixture processes survived and no case left the fixture empty. The 3 breakpoint controls (owner alive) confirmed real exception delivery. Expected contract: a documented kernel-owned boundary prevents continued execution by every inherited member after all control owners disappear, without enumerating descendants after the fact or requiring workload cooperation. I am asking which supported macOS API meets that contract, not asserting that exception ports promise it. Apple DTS asked me to start this thread (Case-ID: 22799543) and will review once I reply with the link. The full reproduction steps and environment details are in the attached text. forum-attachment-reproduction.txt
Replies
3
Boosts
0
Views
445
Activity
1w
macOS: Reliable custody of a sandboxed worker if its controller dies during spawn
Hello, I'm investigating the supported macOS mechanisms for supervising a single unprivileged, sandboxed worker process. The target environment is macOS 15.6 (24G84), Apple Silicon (arm64). The worker is intended to operate under a separate Standard user identity, with tightly restricted capabilities and no requirement to create child processes. The main challenge is the startup failure window: A controller initiates worker creation, but exits unexpectedly before spawn returns or before the worker's identity and authenticated handshake can be independently recorded. In this situation, we need a supported approach to prevent the worker from becoming an unaccounted-for process, or to recover sufficiently trustworthy custody to determine its lifecycle and cleanup state. I have reviewed direct child-process supervision, POSIX process groups, launchd job behaviour, sandbox inheritance, resource limits and process identification mechanisms. I would appreciate guidance on the following: Is there a public, supported macOS API or system service that provides recoverable process custody from initial worker creation, including controller failure during startup? Could an application-associated XPC service or launchd mechanism provide the required lifecycle relationship without granting the worker independent ongoing execution authority? Is generation-safe, audit-token-based process signaling available through a supported public interface, and what are its privilege and acquisition requirements? Is setting a hard RLIMIT_NPROC limit before worker operations a supported way to prevent further fork/spawn activity by an unprivileged worker? What limitations or exceptions should be considered? What can macOS guarantee about process termination and cleanup after controller failure, and what must remain application-level verification? I'm particularly interested in documented guarantees and supported APIs rather than behaviour observed only in tests or private interfaces. Any recommendations or references to Apple documentation would be greatly appreciated. Thank you.
Replies
5
Boosts
0
Views
245
Activity
1w
Supported receiver-confinement guarantee for anonymous XPC connections on macOS 27.0.1
I’m assessing whether the public C XPC APIs provide the recipient guarantee needed for a local security boundary. The proposed path uses a dedicated anonymous listener, a transferred xpc_endpoint_t, and xpc_connection_create_from_endpoint. Before releasing protected data, I need to establish which process occurrence can receive it and whether that binding continues to hold through delivery. Here, “process occurrence” means one running instance, including protection against confusing it with a later instance that reuses its PID. The target reports macOS 27.0.1 (26A434), Darwin 27.0.0, arm64, and xnu-13432.1.9~1/RELEASE_ARM64_T6000. The selected Command Line Tools SDK reports macOS 27.0, SDK build 26A425. These are read-only inventory results; I have not run an XPC prototype for this question. Is there a supported public API contract that lets the sending application, or a separately authorized local verifier, establish before protected data becomes accessible that this connection’s actual receiver is the authenticated process occurrence and remains confined to it for that send? I specifically need to understand whether that guarantee covers endpoint copying or forwarding, repeated or concurrent connections created from one endpoint, process replacement, queued messages, and replies or access-capable attachments. I am asking about the selected C connection API; I do not assume equivalent behavior across the C and Swift session APIs. If a supported mechanism exists, which APIs, OS versions, privileges or entitlements are required, and where is the guarantee documented? If the public API does not expose this guarantee, a clear statement of that limit would help me choose an appropriate transport boundary. The distinction I need to resolve is between authenticating a peer at one point and ensuring that protected outgoing data reaches only that same process occurrence. I am seeking the supported security contract, without requesting access to private implementation details.
Replies
3
Boosts
0
Views
149
Activity
1w
How to distinguish a foreground cold launch from a background task cold launch?
I'm trying to determine why my UIKit application was launched, specifically whether it was launched by the user or by the system to execute a background task. I recently added a BGProcessingTask to update data overnight. Consider this scenario: The user backgrounds the app at 10 AM. A background task is scheduled with earliestBeginDate set to 4 AM the following day. During those 18 hours, iOS terminates the app's process to reclaim memory. iOS later decides to execute the scheduled background task and launches a new app process in the background. My understanding is that this results in a cold launch, including a call to application(_:didFinishLaunchingWithOptions:) and the initialization performed there. This matters because some of our startup initialization triggers network requests that are unnecessary when the app is launched only to perform a background task. Questions 1. Can iOS relaunch a previously terminated app to execute a scheduled BGProcessingTask? I'm referring specifically to termination by the system (for example, memory pressure), not the user force-quitting the application. 2. Is there a reliable way to distinguish a foreground cold launch from a background task cold launch inside application(_:didFinishLaunchingWithOptions:)? I tried checking UIApplication.shared.applicationState, but in my testing it was .background during didFinishLaunchingWithOptions in both scenarios, including when the user launched the app by tapping its icon. Is there another documented API or launch context that reliably identifies why the process was started? I'm aware that iOS provides launch options for certain launch scenarios, but I'm specifically interested in distinguishing a background task-triggered cold launch from a user-initiated foreground cold launch. 3. If this distinction cannot be made reliably during didFinishLaunchingWithOptions, what is the earliest lifecycle callback where I can determine that the app is entering the foreground? For example, should foreground-specific initialization be deferred until scene(_:willConnectTo:options:), sceneWillEnterForeground(_:), or another callback? I'm specifically looking for a documented and reliable lifecycle signal, rather than heuristics or arbitrary delays. The goal is to avoid unnecessary startup initialization and network requests when iOS launches the application solely to execute a background task.
Replies
2
Boosts
0
Views
237
Activity
2w
Subprocess ownership and timeout recovery on Intel macOS Monterey
Hi Quinn, Following your recommendation by email, I’m posting this as a new thread. Thank you again for your guidance on Virtualization.framework. This is a separate question about ordinary host-side subprocess ownership and timeout recovery, not VM cleanup. Target environment: Intel x86_64 macOS Monterey 12.7.6, build 21H1320 Python 3.13.15 Public, supported mechanisms; no root privileges, private APIs or kernel extensions We are verifying a subprocess supervision component with this process structure: Trusted caller process → runner → pytest → private helper → native subprocess Each parent normally owns the consuming wait for its direct child. The private helper exclusively manages signalling and reaping of its native child. Outer processes do not signal saved helper/native PIDs. Cancellation is cooperative, through channels and file/token delivery. The runner observes its fresh pytest child, drains stdout/stderr with bounded retention, and consumes its exact child’s status after exit is observed. The runner, pytest and helper are launched in separate sessions. Consequently, signalling pytest’s process group would not cover the separately sessioned helper and its native child. The unresolved failure case is: A fresh pytest invocation starts. Cancellation delivery fails, or delivery succeeds but the work does not finish. The runner continues observation and bounded output draining within the remaining deadline. The deadline expires while pytest or processes below it may still be alive. The runner reports an unresolved outcome and may exit. The caller also has a bounded deadline and may return without consuming its runner child. Closing capture pipes can cause EPIPE and disturb the child’s cleanup. Exiting a consuming parent also relinquishes its ability to collect that child’s eventual status. The outer caller does not automatically acquire wait rights over pytest or its descendants. Our current policy retains affected files, preserves the original failure, and prevents subsequent tests from starting. We do not treat cancellation delivery, pipe EOF, successful signal delivery, or direct-child reap as proof that every descendant has stopped. This prevents false success, but does not resolve responsibility for work that remains alive. We have considered separating the caller’s response lifetime from the consuming owners’ lifetimes: the caller could return an unresolved response while both existing parents remain alive, draining output and collecting their direct children later. However, keeping them alive adds no termination authority and does not address a crash of either owner. I am not asking for an absolute guarantee against arbitrary kernel failures, or a promise that SIGKILL always completes within a fixed time. I would like to understand the supported architectural approach on Monterey. My questions are: Is retaining the existing consuming parents beyond the response deadline the appropriate pattern, or is there a supported macOS facility that provides a better ownership and recovery boundary? What safe termination authority should those owners retain over their fresh direct children? If process groups are part of the solution, what lifecycle rules are needed to avoid acting on a reused identifier, particularly after leader exit or reaping? Is there a supported way to manage the separately sessioned helper/native work if an intermediate parent exits? Or must each level independently retain its own supervision and cleanup responsibility? If the consuming owner itself crashes, is there a supported recovery mechanism for ordinary subprocesses? Would launchd or XPC materially help, and what limitations would remain for descendants in separate sessions? Which design constraint would you recommend changing: cooperative-only cancellation, the fixed lifetime of the runner, or the process topology? These are our current choices, not restrictions we assume macOS imposes. Our practical goal is a bounded response while an identifiable owner remains responsible for unsettled work, with appropriate termination authority and an honest unresolved outcome when cleanup cannot be established. The immediate qualification scope is only three simple tests, using shell bodies such as exit, kill -9 $$, and echo with ordinary exit statuses. They contain no intentional background work, pipelines or command substitutions. We would prefer a proportionate supported pattern rather than a new general supervision framework. If a reduced example would help clarify the question, I can provide one. Thank you for your time and guidance.
Replies
6
Boosts
0
Views
161
Activity
2w
Diagnosing pre-main latency in a short-lived macOS child process while preserving its parent
I’m looking for a supported way to investigate startup latency before main() in a short-lived native macOS child process, while preserving its original parent-child relationship. Environment macOS 26.6.2, build 25G83. Native arm64 executables. The on-disk /usr/lib/dyld contains the identifier dyld-1387; this is a static observation, not independent verification of all runtime shared-cache components. The diagnostic runs were started manually from normal macOS Terminal. All inputs and target processes are synthetic test fixtures. Execution structure Test supervisor → Watchdog → Observer → Query Observer launches Query using posix_spawn(). Query checks a synthetic target process’s identity using Security.framework and produces a fixed 28-byte result. Observer passes an explicit environment containing only LANG=C and LC_ALL=C. Consequently, exporting DYLD variables in the outer Terminal would not pass them to Query. Our existing test has a 1000 ms Query deadline and requires empty Query stderr. This is an application-defined acceptance requirement, not a claimed macOS timing guarantee. Observed results A historical full regression run timed out at approximately 1001 ms, with no Query result bytes received. That run did not have main-entry instrumentation, so we cannot determine where its time was spent. A later isolated, instrumented run measured: posix_spawn return to Query main entry: 832.687 ms main entry to return: 24.179 ms Observer-measured Query elapsed time: 864 ms Another isolated, instrumented run measured: posix_spawn call duration: 0.179 ms spawn return to main entry: 634.334 ms main entry to return: 6.757 ms Observer-measured Query elapsed time: 647 ms In the third run, getrusage(RUSAGE_SELF) at main entry reported cumulative CPU time of 3.014 ms user and 2.583 ms system. Before main returned, the cumulative total was 8.088 ms. Timeline measurements used CLOCK_MONOTONIC. Interpretation limits These successful diagnostic runs do not explain or resolve the historical timeout. Instrumentation changes the executable, and cache state and scheduling may differ. The CPU and wall-clock measurements cover different intervals. Subtracting them would not give an exact waiting-time measurement. We cannot currently attribute the delay to dyld, scheduling, security checks, IPC, or I/O. Diagnostic constraints We want to preserve the original parent-child relationship and avoid system-wide collection, disabling security protections, or silently changing permissions. We have not established that the Instruments App Launch configuration available to us can capture this child’s earliest startup phases while restricting collection to Query. The historical DYLD_PRINT_STATISTICS options are not documented in the installed dyld manual. Attaching a sampling tool after obtaining the PID may miss the relevant startup interval and may perturb this short-lived process. Questions What supported tool or API on this macOS version can distinguish startup phases before main() for this posix_spawn-created child? Can collection itself be restricted to Query, rather than collecting system-wide data and filtering the report afterward? What permissions are required, which early phases remain unobservable, and how much observer perturbation should we expect? If these constraints cannot all be met, what is the smallest necessary change to the diagnostic setup? What minimal sample project and evidence would be most useful for further investigation? I have preserved the original failure and subsequent diagnostic evidence, but do not yet have a standalone Xcode sample that reliably reproduces the historical timeout. I’m requesting guidance on an appropriate measurement method, not asserting that this is a confirmed macOS defect.
Replies
4
Boosts
0
Views
150
Activity
2w
macOS XPC: Can incoming message size be bounded before payload allocation?
Hello, I'm designing a local macOS helper service (minimum deployment target: macOS 13) that performs one fixed syntax-validation operation. The submitted source is never executed. The security contract requires: A maximum incoming transport request size of 327,680 bytes. Immediate rejection when the 327,681st byte is encountered, without an allocation proportional to an unbounded sender-controlled payload. No application-level response for an oversized transport request, followed by termination of the affected connection. Complete application responses limited to 65,536 bytes, without treating truncated output as successful. I've reviewed the public XPC APIs, including xpc_data_get_length, xpc_connection_cancel, and xpc_connection_set_peer_code_signing_requirement. The remaining uncertainty is whether XPC can enforce a receiver-side message-size limit before materializing the incoming payload. My questions are: Does any public XPC API on macOS 13+ provide a documented maximum incoming message size that is enforced before payload materialization or proportional allocation? If not, is the entire incoming XPC message necessarily materialized before the application event handler receives it? Is there a supported XPC design for guaranteeing bounded receiver memory with untrusted input, or should this requirement use a different local transport, such as an AF_UNIX SOCK_STREAM socket? What guarantees does xpc_connection_cancel provide regarding connection termination, pending messages, and prevention of connection reuse after detecting malformed or oversized input? I'm specifically looking for documented platform guarantees rather than behavior that happens to work in testing. Thank you!
Replies
4
Boosts
0
Views
278
Activity
2w
Supported libSystem state after a LaunchDaemon permanently drops privileges
I am testing a fixed signed LaunchDaemon startup program that uses setgroups, setgid and setuid to establish a dedicated non-root identity before loading its service library or creating an application XPC listener. This follows the single-process, deferred-library direction discussed in DTS thread 844906. The remaining question is the supported treatment of system-runtime state initialized before the credential transition. Test environment: Apple silicon, macOS 27.0.1 / Darwin 27.0.0, hardened runtime, no special entitlements. The host links only libSystem and has no application constructors. This is a temporary diagnostic, not an installed product or a file-operation service. Our test verifies real, effective and saved UID/GID, the exact supplementary group vector and failed attempts to regain root. After the transition, a read-only own-task Mach inventory still sees a voucher even though successful task/current-thread voucher getters return null. It also sees one send+receive endpoint without an alias to any of the queried special/registered roles. Ordinary hardened launchd controls in both the login GUI and user domains also have a voucher and such an endpoint. Their recorded endpoint attributes match the post-drop test: empty queue, sequence 1, make-send count 1, send rights present, no send-once rights, port sets or notification requests. We do not treat this as proof that the objects or authority are equivalent. No messages are sent to the unidentified endpoint and no runtime-owned rights are destroyed. In a separate ordinary-user test, public voucher recipe extraction reports only a BANK attribute. Published libdispatch source describes a default task-bank voucher stored separately from the current thread's voucher slot. Published XNU source captures identity when bank context is initialized. We have not established the corresponding lifecycle or authority implications on this OS release, and do not claim that the observed voucher retains root authority. For this startup arrangement, what supported public contract should an application use to establish that libSystem's retained runtime context does not preserve usable pre-drop administrator authority before loading service code? Is there a supported sanitization step, or a specific documented OS trust assumption under which leaving that state intact is intended? If the combination of exact group reduction, deferred service loading and launchd Mach-service check-in cannot support that boundary, which public architecture should we use instead? We are seeking a documented arrangement or a clear limit on the guarantee, rather than a private reset API or an explanation of every internal endpoint. We have not used same-PID exec, a root supervisor, private APIs, or a broad port-type allowlist. Relevant documentation or a minimal public sample would help.
Replies
1
Boosts
0
Views
304
Activity
2w
macOS 14+: Safely supervising worker-created child processes.
Hello Apple Developer Community, We are developing a macOS application with a minimum deployment target of macOS 14.0. We are investigating a process-supervision safety problem involving the following topology: Root → Worker → Child The Worker creates the Child using native process APIs and is responsible for supervising its lifecycle. The critical failure scenario Worker successfully creates Child. Child exists, but its verified process identity has not yet been communicated to Root. Worker unexpectedly terminates before completing the identity handoff. Root must avoid signaling an unrelated process while ensuring that an untracked Child cannot continue executing without authorization. Our safety requirements Independently establish Child's exact process-lifetime identity. Prevent unsafe process signaling caused by PID reuse. Handle Worker failure before identity handoff. Verify process termination and disposition. Avoid relying on private APIs or restricted entitlements. Maintain compatibility with macOS 14 and later. What we have investigated We have reviewed posix_spawn, waitpid, process observation APIs, audit-token-based process identification and signaling, Endpoint Security, and launchd-based supervision. We understand that Endpoint Security FORK events are notifications rather than authorization events, and that dropped notifications may prevent complete birth tracking. We also found es_new_descendants_client in the macOS 27 SDK, but it requires an Endpoint Security entitlement and does not meet our current macOS 14 deployment requirements. We understand that a process cannot automatically use waitpid to reap a grandchild merely because the intermediate parent has terminated. Our questions Is there a publicly supported macOS 14+ API or process-supervision mechanism that can reliably establish the identity of a Worker-created Child even if Worker terminates before communicating that identity? Is there a supported approach for safely containing such a Child when its identity is not yet known to Root? Can audit-token-based signaling provide sufficient process-lifetime identity guarantees for this scenario, and what minimum macOS version supports the relevant APIs? Is there a supported mechanism for independently verifying Child termination when Root is not its direct parent? If this cannot be guaranteed using public APIs, would Apple recommend changing the architecture so that Root directly creates and supervises Child? We are not requesting private API access or Endpoint Security entitlements. We would appreciate guidance on the supported macOS process-lifecycle contracts before proceeding with implementation. Thank you for your assistance.
Replies
5
Boosts
0
Views
565
Activity
2w
C-XPC on macOS 14: Do connection EUID/ASID and message-derived SecCode identify the same sender?
Platform / environment Minimum deployment target: macOS 14.0. Development environment: macOS 26.3, Xcode 26.6, macOS SDK 26.5, Swift 6.3.3. We are evaluating public C-XPC and Security.framework APIs; we have not yet validated this identity model over a real C-XPC connection. Context A per-user, signed Runtime Host accepts a connection from a separately signed client. Let peer be the accepted C-XPC peer connection, and receivedMessage the original request dictionary delivered by that connection's event handler. Our admission policy requires both (a) the effective UID and audit session of the actual message sender and (b) validation of that sender's dynamic code against an independently configured code-signing requirement. No application-level authority is granted before these checks. API sequence under review We would first read xpc_connection_get_euid(peer) and xpc_connection_get_asid(peer), then obtain a dynamic code reference via SecCodeCreateWithXPCMessage(receivedMessage, kSecCSDefaultFlags, &code). We would validate that reference with SecCodeCheckValidity(code, kSecCSDefaultFlags, approvedRequirement), where approvedRequirement is configured independently of the peer, and finally inspect the required signing information with SecCodeCopySigningInformation. Reading signing information is not a substitute for code validation. Question On macOS 14, is there a documented, supported guarantee that the connection-level EUID/ASID and the message-derived SecCode refer to the same process occurrence and the actual sender of this particular received request? The connection getters describe attributes captured when the connection was established, while SecCodeCreateWithXPCMessage derives a dynamic-code reference from the original received XPC dictionary. We do not assume that these APIs provide an atomic identity snapshot or prove that their observations refer to the same sender process instance. In particular, what are the limits of any such guarantee when messages or messaging capabilities are forwarded, a process calls exec, a process exits or is replaced, credentials or audit sessions change, or a connection is interrupted and re-established? What if the sender's state changes between message reception and completion of the validation sequence? Request for a supported alternative If this API sequence does not establish that correspondence, which public APIs available on macOS 14 can provide the effective UID, audit session ID, and dynamic-code identity from the same received-message provenance? We are not considering PID-only lookup, private audit-token access, or caller-supplied identity claims. A clarification that the requested guarantee is unavailable would also be valuable. References xpc_connection_get_euid xpc_connection_get_asid Apple DTS: Validating Signature Of XPC Process
Replies
0
Boosts
0
Views
107
Activity
3w
Supported completeness and lifecycle guarantees for es_new_descendants_client
Hello Apple Developer Technical Support, I am evaluating es_new_descendants_client for a local command runner that must report success only after its workload and every process descended from that workload have exited. If observation is incomplete or ambiguous, the runner must report failure. This is a design inquiry, not a report of a reproduced operating-system defect; no entitled prototype has been tested. The proposed observer would create its client and subscribe to lifecycle notifications before launching any workload. It would maintain a registry using process-lifetime identities, add processes on creation and remove them on exit. An unmatched event, missing required field, detected loss or observer failure would invalidate the run. It would consider closure only after all registered workload processes had exited. We have not established that these rules are sufficient. Could you clarify which of the following properties are supported API guarantees, and identify any that applications must not rely on? A documented reference or an explicit statement that a guarantee is unavailable would both help. Please identify applicable macOS/SDK versions and any known version-dependent limitations. 1. Membership and creation-event coverage Does the observed subtree retain a process and all of its future descendants after its original parent exits, it is reparented, it double-forks, or it changes process group/session with setpgid or setsid? Could a process remain observable for exit while creation events for its children become invisible? For a workload launched after successful subscription, does every successful process-creation path—including fork, vfork and posix_spawn—produce a lifecycle event sufficient to register the new process before closure can be declared? Which event and identity fields should be used for each path, including a child that exits without a successful exec? Does the calling observer receive the necessary event for its own initial workload launch? 2. Ordering and the meaning of exit Is there a supported per-client ordering guarantee that every child-creation event from a process is delivered before that process's exit notification, including concurrent creation and exit? Can the child's events arrive before the event that introduces that child? Please distinguish kernel enqueue order, handler delivery order and any processing order the application must impose. At what lifecycle boundary is ES_EVENT_TYPE_NOTIFY_EXIT generated? Does it establish that the identified process can no longer execute or initiate writes, or can relevant activity continue after the notification? We would not equate process exit with filesystem durability or completion of work already delegated to other processes. 3. Muting and other visibility filters Does a newly created descendants client have default process, path or target-path mutes that can suppress fork/exit notifications? What supported sequence of configuration and inspection calls establishes complete lifecycle visibility before launch, including mute inversion and executable-path changes? Apart from subscription and muting, are there policy, security, rate-limit or client-type exclusions that can suppress those events? Which suppressed events, if any, are intentionally absent from the sequence counter rather than reported as drops? 4. Sequence numbers and loss detection The global_seq_num documentation requires message version greater than 4. Is that field guaranteed for descendants-client lifecycle messages? Do notifications concerning the calling observer and its descendants use the same per-client sequence? How can a client establish a valid initial baseline and detect loss before its first received message? Is every dropped subscribed, unmuted lifecycle event reflected in the next delivered sequence number? What counter reset, wraparound or client-recreation rules must be handled? Would the proposed registry rule make terminal loss fail safely—for example, a lost final exit leaves a process registered—under the supported ordering and visibility semantics? Or is there a counterexample in which the registry can become empty while an unobserved descendant survives? 5. Synchronization, observer failure and delegated work Does es_sync_client provide any loss/completeness information beyond draining preceding queued messages? Its documented callbacks also run for a destroyed or null client, so we would not interpret callback arrival alone as successful completion. Is there a supported mechanism to distinguish a healthy drain from invalidation? What does “instigates” cover for this client? In particular, can it observe or attribute work executed by existing launchd/XPC services, or by unrelated processes receiving file descriptors? We would treat such work as outside a lineage-only closure claim unless it is explicitly covered or independently excluded. Does this client provide any supported protection against a same-UID workload stopping, killing or otherwise interfering with its observer, or must that isolation be supplied separately? Observer failure would invalidate the run; we are not assuming ES supplies a write barrier for evidence files. 6. Supported cleanup and deployment Is there a supported public mechanism to signal a non-child descendant by process-lifetime identity, without a PID-reuse race between observing it and sending a signal? Is there a recommended approach if the observer cannot wait on that process? We do not want to depend on private libproc functions as an application contract. Finally, is this use case eligible for com.apple.developer.endpoint-security.client in a standalone signed command-line observer, and what supported signing/provisioning or packaging requirements apply? This is a request for guidance, not an entitlement application. Our central question is whether supported APIs can establish complete descendant-process closure under these constraints. If they cannot, we would appreciate a clear statement of that limitation or a supported alternative. Thank you. Documentation consulted: es_new_descendants_client es_sync_client global_seq_num es_process_t
Replies
6
Boosts
0
Views
882
Activity
3w
Could not set environment: 150: Operation not permitted while System Integrity Protection is engaged
Hi. After the recent update of Ventura to 13.4 and Big Sur to 11.7.7 all of a sudden "launchctl setenv" returns the following errors. Could not set environment: 150: Operation not permitted while System Integrity Protection is engaged Is there any workaround to fix this?
Replies
7
Boosts
0
Views
5.4k
Activity
3w