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
How can a macOS observer verify child creation and reap after the spawning process exits?
On Apple silicon macOS 27.2 build 26B123, consider a launchd-managed supervisor making one posix_spawn call to start a dedicated worker. The supervisor may exit before receiving the PID or before it can wait for the child. Is there a supported API or OS-issued record that lets a surviving observer verify what happened to that one attempt? Can the observer distinguish an attempt that created no child from one that created a child before the caller received the PID? What stable identifier ties creation and any exec transition to that attempt? If the supervisor exits, which component actually performs the reap? Can the observer verify the same child's exit status, completed reap, and absence of surviving descendants after restarting? Please identify the supported macOS versions, privileges, record source, correlation fields, and any loss or retention limits. If no supported record covers a step, please identify that boundary.
0
0
40
3h
Can macOS enforce a 512 MiB combined address-space cap before child code runs?
On Apple silicon macOS, is there a supported public mechanism that can enforce a hard combined mapped virtual address-space ceiling of 512 MiB for a parent process and its new child from the first charged creation step through loading the child's executable image, before the child runs any application code? The current investigation targets macOS build 26B123 on arm64. We need to know how the supported limit accounts for inherited maps, shared-region reservations and image mappings during process creation. If the supported route is to partition the ceiling between per-process limits, please specify whether the child limit applies before its first charged map and how a limit failure is reported. Please identify the public API or documentation, supported OS versions and required setup. A control that only applies to resident memory or starts after application code begins would not cover this question.
0
0
65
13h
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.
7
0
256
2d
Title: Supported macOS PID reservation for an exited but unreaped direct child
Title: Supported macOS PID reservation for an exited but unreaped direct child I'm designing a process-lifecycle experiment on Apple silicon, initially targeting macOS 26.7.2 (build 25G332). A trusted parent directly launches a foreground child using posix_spawn(). The parent remains alive, exclusively owns reaping, preserves child exit status, and never sets SIGCHLD to SIG_IGN or enables SA_NOCLDWAIT. The parent may send kill(child_pid, SIGKILL) before obtaining the child's terminal status through waitpid(). POSIX.1-2008 §3.295 describes the PID as the last resource released when a process's lifetime ends. Section 4.13 prohibits PID reuse before that lifetime ends. Could Apple DTS clarify the supported macOS contract for this sequence? If the child exits immediately before the kill() call but remains unreaped, is its PID guaranteed not to be reassigned to another process while the original parent retains exclusive reaping authority? Does this guarantee apply to a child created through posix_spawn() on current Apple silicon macOS releases? Are there documented exceptions beyond automatic status disposal, competing reapers and parent termination? What result should the parent expect when kill() targets an already-exited but unreaped child? The design serialises signaling and reaping, and never signals the numeric PID after status consumption. This question concerns identity-safe signal targeting, not whether successful kill() establishes termination. The latter is separately verified using waitpid(). I'm seeking a supported API contract rather than empirical observations or private kernel implementation details. Thank you.
1
0
52
2d
iPadOS 26.4+ significantly reduced per-app memory limit from 6GB to 3GB on 8GB iPad, breaking memory-intensive apps
Summary: Starting from iPadOS 26.4, the maximum memory available to a single app has been reduced from approximately 6GB to 3GB on an 8GB iPad. This change persists in iPadOS 26.5 and has not been addressed. This breaks core functionality of memory-intensive applications such as 3D scanning apps that require large amounts of RAM to process models. Device: iPad with 8GB RAM Affected versions: iPadOS 26.4, iPadOS 26.5 Working version: iPadOS 26.0 / 26.1 / 26.2 / 26.3 Measured Data: iPadOS 26.0–26.3: App available memory ≈ 6GB (75% of total RAM) iPadOS 26.4–26.5: App available memory ≈ 3GB (37.5% of total RAM) Measurement method: Apple system API Impact: This is a regression, not expected behavior. The available memory per app has been cut by 50% without any official documentation or release notes mentioning this change. As a result, our 3D scanning application crashes immediately when attempting to process 3D models on iPadOS 26.4 and later. The app requires substantial RAM to load and process 3D model data. With only 3GB available, memory allocation fails during model processing, causing the app to crash (EXC_RESOURCE / OOM kill). This core functionality was working correctly on iPadOS 26.3 and earlier with the same device and same app binary. This regression makes our app's primary feature completely unusable for all users on iPadOS 26.4+. Steps to Reproduce: On an 8GB iPad, install iPadOS 26.0 Measure available app memory using Apple system API Upgrade to iPadOS 26.4 or 26.5 Measure available app memory again Observe: available memory drops from ~6GB to ~3GB Expected Result: Available memory per app should remain consistent across minor OS updates, or any changes should be documented. Actual Result: Available memory per app dropped by 50% starting in iPadOS 26.4, with no documentation of this change. Additional Notes: Disabling Apple Intelligence does not resolve the issue This issue was not fixed in iPadOS 26.5 Other developers have reported increased crash rates starting in iPadOS 26.4 (Apple Developer Forums)
18
1
3.8k
3d
iOS app running on macOS 27.0.1 terminated on suspension due to a Metal archiveUsage.db file lock (0xDEAD10CC)
Hello, We are investigating an issue where our iOS app, running as a “Designed for iPad” app on an Apple Silicon Mac, is terminated when it is suspended in the background. Environment OS: macOS 27.0.1 Hardware: Apple Silicon Mac App type: An iOS/iPadOS app running on Mac, rather than a separately developed macOS app The app uses Core Image’s CIContext to generate some image effects Steps to reproduce Launch the app on Mac and start playing a podcast. Move the app to the background. Start playback on another device. Our app’s cross-device playback coordination pauses playback on the Mac. After a short period, the Mac app is terminated. We have also observed similar termination after visiting a screen that uses Core Image image effects. Actual result The debugger reports: Terminated due to signal 9 RunningBoard logs indicate that the app was terminated with code 0xDEAD10CC because it was suspended while holding a disallowed shared file lock. The file identified in the log is: /var/folders/.../C/app.podcast.cosmos/app.podcast.cosmos/com.apple.metal/archiveUsage.db/lock.mdb The relevant log message includes: suspended while holding a shared file lock Investigation so far Using breakpoints on open and openat, we captured a call stack corresponding to: App creates a CIContext → Core Image CI::MetalContext → Metal recordBinaryArchiveUsage → archiveUsage.db/lock.mdb is opened We also tried: CIContext(options: [.useSoftwareRenderer: true]) However, in our test environment, we still observed Metal initialization and access to the relevant cache files. This option did not avoid the issue. For the gradient-mask generation code we had identified, we replaced the Core Image implementation with a CPU implementation using CGContext and CGGradient, avoiding CIContext creation on that path. After repeatedly testing the same reproduction steps, we could no longer reproduce the termination in that scenario. This suggests a connection to the Metal cache file lock accessed during Core Image initialization. However, we have not established the exact lifetime or internal owner of the lock, and we have not confirmed a thread deadlock. Questions Is this a known issue involving Core Image/Metal and suspension of iOS apps running on macOS 27.0.1? Why would a system-managed Metal cache file lock cause the app to be terminated with 0xDEAD10CC when suspended? Is there a recommended context configuration, resource cleanup procedure, or lifecycle handling approach that allows us to continue using Core Image safely in this environment?
1
0
62
3d
有运算密集型的任务需要运行较长时间,用户在前台触发后不希望一直在前台等待任务完成,希望在后台持续运行并且有较高的CPU优先级,在前台轻负载情况下让这个后台任务性能保持和前台时接近的性能和时延,请问iOS上有这样的方案吗?
需要满足 (1)后台保活,在后台时任务仍然能一直运行直到任务完成 (2)任务在后台运行时,且前台负载较低时让任务分配尽量多的CPU资源,保持任务的性能和前台时接近 (3)需要使用GPU和NPU,需要跑AI模型,如果可以用GPU就更好,(GPU不跑也行) (4)方案合法,能上架苹果APP Store. 可以通过蓝牙连接来进行后台保活,这个任务本身就需要通过蓝牙连接一个外设,但是这种保活方式任务在后台时CPU权限较低,性能时延劣化很严重。 任务本身是类似做图片/视频处理的任务,需要跑几秒到几分钟的量级,最好可以尽量多地跑久一些。 我们试过了,后台保活后性能都大幅下降,降了6~10倍,体验较差 有没有做过类似的后台任务的,最终做到前后台性能接近的(前台空负载时)?
1
0
161
3d
有运算密集型的任务需要运行较长时间,用户在前台触发后不希望一直在前台等待任务完成,希望在后台持续运行并且有较高的CPU优先级,在前台轻负载情况下让这个后台任务性能保持和前台时接近的性能和时延,请问iOS上有这样的方案吗?
需要满足 (1)后台保活,在后台时任务仍然能一直运行直到任务完成 (2)任务在后台运行时,且前台负载较低时让任务分配尽量多的CPU资源,保持任务的性能和前台时接近 (3)需要使用GPU和NPU,需要跑AI模型,如果可以用GPU就更好,(GPU不跑也行) (4)方案合法,能上架苹果APP Store. 可以通过蓝牙连接来进行后台保活,这个任务本身就需要通过蓝牙连接一个外设,但是这种保活方式任务在后台时CPU权限较低,性能时延劣化很严重。 任务本身是类似做图片/视频处理的任务,需要跑几秒到几分钟的量级,最好可以尽量多地跑久一些。 我们试过了,后台保活后性能都大幅下降,降了6~10倍,体验较差 有没有做过类似的后台任务的,最终做到前后台性能接近的(前台空负载时)?
0
0
65
4d
Pre-activation authorization and inactive connection cleanup for a launchd Mach service
I am evaluating the supported macOS C XPC lifecycle for a separately installed system-domain Mach service. This is a design/documentation question, not a reported crash or a tested OS-specific failure. Please identify applicable macOS/SDK versions and public API guarantees; no installed SDK capability is being assumed. The threat model includes an unprivileged process running as the worker's user. The OS and privileged administrator are trusted. Executables and role assignments would require independently protected approval. Matching a code signature alone is not intended to grant an issuer role. Two API boundaries affect whether the service can be authorized before activation: Binding an actual launch instance to protected enrollment. Is there a supported public API or enforceable launch-environment constraint that can distinguish an instance launched through an approved system-domain job/enrollment from direct invocation of the same approved executable? The required distinction is the actual job/executable launch transaction before service activation, not a process-provided label, PID/PPID lookup, copied install record, or signature alone. If launch constraints can enforce only a narrower property, what exactly is that property and its minimum supported version? If no public mechanism provides the stronger binding, confirmation of that limit would be useful. This question does not assume an XPC peer requirement can establish job origin or issuer authority. Disposing of a newly owned inactive connection after setup failure. Suppose xpc_connection_create_mach_service returns a caller-owned inactive client or listener, but preactivation policy setup then fails, for example xpc_connection_set_peer_code_signing_requirement returns an error. What is the documented safe cleanup sequence if transport activation has not been authorized? The xpc_connection_activate documentation warns that last-release of a created inactive connection is undefined. The cancellation documentation describes asynchronous unwinding, but I have not found an explicit exception for last-release of a never-activated, canceled object. Does a supported cancel/release sequence exist? If activation is required even for disposal, what effects can that cleanup activation cause and what guarantees apply? I am asking about a newly created owned object, not an incoming borrowed peer that a listener can reject by canceling and returning. Relevant references already consulted: https://developer.apple.com/documentation/xpc/xpc_connection_activate(_:) https://developer.apple.com/documentation/xpc/xpc_connection_cancel(_:) https://developer.apple.com/documentation/xpc/xpc_connection_set_event_handler(::) https://developer.apple.com/forums/thread/837286 (received-message checking versus initial outgoing delivery) An API reference, versioned contract, or explicit statement that either guarantee is unavailable would help determine the safe supported boundary. I am not requesting private APIs or a workaround that treats a caller assertion as authorization.
1
0
122
5d
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
629
1w
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
217
1w
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
321
1w
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
173
1w
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
129
1w
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
156
1w
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
101
2w
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
476
2w
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
301
2w
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
189
2w
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
272
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
How can a macOS observer verify child creation and reap after the spawning process exits?
On Apple silicon macOS 27.2 build 26B123, consider a launchd-managed supervisor making one posix_spawn call to start a dedicated worker. The supervisor may exit before receiving the PID or before it can wait for the child. Is there a supported API or OS-issued record that lets a surviving observer verify what happened to that one attempt? Can the observer distinguish an attempt that created no child from one that created a child before the caller received the PID? What stable identifier ties creation and any exec transition to that attempt? If the supervisor exits, which component actually performs the reap? Can the observer verify the same child's exit status, completed reap, and absence of surviving descendants after restarting? Please identify the supported macOS versions, privileges, record source, correlation fields, and any loss or retention limits. If no supported record covers a step, please identify that boundary.
Replies
0
Boosts
0
Views
40
Activity
3h
Can macOS enforce a 512 MiB combined address-space cap before child code runs?
On Apple silicon macOS, is there a supported public mechanism that can enforce a hard combined mapped virtual address-space ceiling of 512 MiB for a parent process and its new child from the first charged creation step through loading the child's executable image, before the child runs any application code? The current investigation targets macOS build 26B123 on arm64. We need to know how the supported limit accounts for inherited maps, shared-region reservations and image mappings during process creation. If the supported route is to partition the ceiling between per-process limits, please specify whether the child limit applies before its first charged map and how a limit failure is reported. Please identify the public API or documentation, supported OS versions and required setup. A control that only applies to resident memory or starts after application code begins would not cover this question.
Replies
0
Boosts
0
Views
65
Activity
13h
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
7
Boosts
0
Views
256
Activity
2d
Title: Supported macOS PID reservation for an exited but unreaped direct child
Title: Supported macOS PID reservation for an exited but unreaped direct child I'm designing a process-lifecycle experiment on Apple silicon, initially targeting macOS 26.7.2 (build 25G332). A trusted parent directly launches a foreground child using posix_spawn(). The parent remains alive, exclusively owns reaping, preserves child exit status, and never sets SIGCHLD to SIG_IGN or enables SA_NOCLDWAIT. The parent may send kill(child_pid, SIGKILL) before obtaining the child's terminal status through waitpid(). POSIX.1-2008 §3.295 describes the PID as the last resource released when a process's lifetime ends. Section 4.13 prohibits PID reuse before that lifetime ends. Could Apple DTS clarify the supported macOS contract for this sequence? If the child exits immediately before the kill() call but remains unreaped, is its PID guaranteed not to be reassigned to another process while the original parent retains exclusive reaping authority? Does this guarantee apply to a child created through posix_spawn() on current Apple silicon macOS releases? Are there documented exceptions beyond automatic status disposal, competing reapers and parent termination? What result should the parent expect when kill() targets an already-exited but unreaped child? The design serialises signaling and reaping, and never signals the numeric PID after status consumption. This question concerns identity-safe signal targeting, not whether successful kill() establishes termination. The latter is separately verified using waitpid(). I'm seeking a supported API contract rather than empirical observations or private kernel implementation details. Thank you.
Replies
1
Boosts
0
Views
52
Activity
2d
iPadOS 26.4+ significantly reduced per-app memory limit from 6GB to 3GB on 8GB iPad, breaking memory-intensive apps
Summary: Starting from iPadOS 26.4, the maximum memory available to a single app has been reduced from approximately 6GB to 3GB on an 8GB iPad. This change persists in iPadOS 26.5 and has not been addressed. This breaks core functionality of memory-intensive applications such as 3D scanning apps that require large amounts of RAM to process models. Device: iPad with 8GB RAM Affected versions: iPadOS 26.4, iPadOS 26.5 Working version: iPadOS 26.0 / 26.1 / 26.2 / 26.3 Measured Data: iPadOS 26.0–26.3: App available memory ≈ 6GB (75% of total RAM) iPadOS 26.4–26.5: App available memory ≈ 3GB (37.5% of total RAM) Measurement method: Apple system API Impact: This is a regression, not expected behavior. The available memory per app has been cut by 50% without any official documentation or release notes mentioning this change. As a result, our 3D scanning application crashes immediately when attempting to process 3D models on iPadOS 26.4 and later. The app requires substantial RAM to load and process 3D model data. With only 3GB available, memory allocation fails during model processing, causing the app to crash (EXC_RESOURCE / OOM kill). This core functionality was working correctly on iPadOS 26.3 and earlier with the same device and same app binary. This regression makes our app's primary feature completely unusable for all users on iPadOS 26.4+. Steps to Reproduce: On an 8GB iPad, install iPadOS 26.0 Measure available app memory using Apple system API Upgrade to iPadOS 26.4 or 26.5 Measure available app memory again Observe: available memory drops from ~6GB to ~3GB Expected Result: Available memory per app should remain consistent across minor OS updates, or any changes should be documented. Actual Result: Available memory per app dropped by 50% starting in iPadOS 26.4, with no documentation of this change. Additional Notes: Disabling Apple Intelligence does not resolve the issue This issue was not fixed in iPadOS 26.5 Other developers have reported increased crash rates starting in iPadOS 26.4 (Apple Developer Forums)
Replies
18
Boosts
1
Views
3.8k
Activity
3d
iOS app running on macOS 27.0.1 terminated on suspension due to a Metal archiveUsage.db file lock (0xDEAD10CC)
Hello, We are investigating an issue where our iOS app, running as a “Designed for iPad” app on an Apple Silicon Mac, is terminated when it is suspended in the background. Environment OS: macOS 27.0.1 Hardware: Apple Silicon Mac App type: An iOS/iPadOS app running on Mac, rather than a separately developed macOS app The app uses Core Image’s CIContext to generate some image effects Steps to reproduce Launch the app on Mac and start playing a podcast. Move the app to the background. Start playback on another device. Our app’s cross-device playback coordination pauses playback on the Mac. After a short period, the Mac app is terminated. We have also observed similar termination after visiting a screen that uses Core Image image effects. Actual result The debugger reports: Terminated due to signal 9 RunningBoard logs indicate that the app was terminated with code 0xDEAD10CC because it was suspended while holding a disallowed shared file lock. The file identified in the log is: /var/folders/.../C/app.podcast.cosmos/app.podcast.cosmos/com.apple.metal/archiveUsage.db/lock.mdb The relevant log message includes: suspended while holding a shared file lock Investigation so far Using breakpoints on open and openat, we captured a call stack corresponding to: App creates a CIContext → Core Image CI::MetalContext → Metal recordBinaryArchiveUsage → archiveUsage.db/lock.mdb is opened We also tried: CIContext(options: [.useSoftwareRenderer: true]) However, in our test environment, we still observed Metal initialization and access to the relevant cache files. This option did not avoid the issue. For the gradient-mask generation code we had identified, we replaced the Core Image implementation with a CPU implementation using CGContext and CGGradient, avoiding CIContext creation on that path. After repeatedly testing the same reproduction steps, we could no longer reproduce the termination in that scenario. This suggests a connection to the Metal cache file lock accessed during Core Image initialization. However, we have not established the exact lifetime or internal owner of the lock, and we have not confirmed a thread deadlock. Questions Is this a known issue involving Core Image/Metal and suspension of iOS apps running on macOS 27.0.1? Why would a system-managed Metal cache file lock cause the app to be terminated with 0xDEAD10CC when suspended? Is there a recommended context configuration, resource cleanup procedure, or lifecycle handling approach that allows us to continue using Core Image safely in this environment?
Replies
1
Boosts
0
Views
62
Activity
3d
有运算密集型的任务需要运行较长时间,用户在前台触发后不希望一直在前台等待任务完成,希望在后台持续运行并且有较高的CPU优先级,在前台轻负载情况下让这个后台任务性能保持和前台时接近的性能和时延,请问iOS上有这样的方案吗?
需要满足 (1)后台保活,在后台时任务仍然能一直运行直到任务完成 (2)任务在后台运行时,且前台负载较低时让任务分配尽量多的CPU资源,保持任务的性能和前台时接近 (3)需要使用GPU和NPU,需要跑AI模型,如果可以用GPU就更好,(GPU不跑也行) (4)方案合法,能上架苹果APP Store. 可以通过蓝牙连接来进行后台保活,这个任务本身就需要通过蓝牙连接一个外设,但是这种保活方式任务在后台时CPU权限较低,性能时延劣化很严重。 任务本身是类似做图片/视频处理的任务,需要跑几秒到几分钟的量级,最好可以尽量多地跑久一些。 我们试过了,后台保活后性能都大幅下降,降了6~10倍,体验较差 有没有做过类似的后台任务的,最终做到前后台性能接近的(前台空负载时)?
Replies
1
Boosts
0
Views
161
Activity
3d
有运算密集型的任务需要运行较长时间,用户在前台触发后不希望一直在前台等待任务完成,希望在后台持续运行并且有较高的CPU优先级,在前台轻负载情况下让这个后台任务性能保持和前台时接近的性能和时延,请问iOS上有这样的方案吗?
需要满足 (1)后台保活,在后台时任务仍然能一直运行直到任务完成 (2)任务在后台运行时,且前台负载较低时让任务分配尽量多的CPU资源,保持任务的性能和前台时接近 (3)需要使用GPU和NPU,需要跑AI模型,如果可以用GPU就更好,(GPU不跑也行) (4)方案合法,能上架苹果APP Store. 可以通过蓝牙连接来进行后台保活,这个任务本身就需要通过蓝牙连接一个外设,但是这种保活方式任务在后台时CPU权限较低,性能时延劣化很严重。 任务本身是类似做图片/视频处理的任务,需要跑几秒到几分钟的量级,最好可以尽量多地跑久一些。 我们试过了,后台保活后性能都大幅下降,降了6~10倍,体验较差 有没有做过类似的后台任务的,最终做到前后台性能接近的(前台空负载时)?
Replies
0
Boosts
0
Views
65
Activity
4d
Pre-activation authorization and inactive connection cleanup for a launchd Mach service
I am evaluating the supported macOS C XPC lifecycle for a separately installed system-domain Mach service. This is a design/documentation question, not a reported crash or a tested OS-specific failure. Please identify applicable macOS/SDK versions and public API guarantees; no installed SDK capability is being assumed. The threat model includes an unprivileged process running as the worker's user. The OS and privileged administrator are trusted. Executables and role assignments would require independently protected approval. Matching a code signature alone is not intended to grant an issuer role. Two API boundaries affect whether the service can be authorized before activation: Binding an actual launch instance to protected enrollment. Is there a supported public API or enforceable launch-environment constraint that can distinguish an instance launched through an approved system-domain job/enrollment from direct invocation of the same approved executable? The required distinction is the actual job/executable launch transaction before service activation, not a process-provided label, PID/PPID lookup, copied install record, or signature alone. If launch constraints can enforce only a narrower property, what exactly is that property and its minimum supported version? If no public mechanism provides the stronger binding, confirmation of that limit would be useful. This question does not assume an XPC peer requirement can establish job origin or issuer authority. Disposing of a newly owned inactive connection after setup failure. Suppose xpc_connection_create_mach_service returns a caller-owned inactive client or listener, but preactivation policy setup then fails, for example xpc_connection_set_peer_code_signing_requirement returns an error. What is the documented safe cleanup sequence if transport activation has not been authorized? The xpc_connection_activate documentation warns that last-release of a created inactive connection is undefined. The cancellation documentation describes asynchronous unwinding, but I have not found an explicit exception for last-release of a never-activated, canceled object. Does a supported cancel/release sequence exist? If activation is required even for disposal, what effects can that cleanup activation cause and what guarantees apply? I am asking about a newly created owned object, not an incoming borrowed peer that a listener can reject by canceling and returning. Relevant references already consulted: https://developer.apple.com/documentation/xpc/xpc_connection_activate(_:) https://developer.apple.com/documentation/xpc/xpc_connection_cancel(_:) https://developer.apple.com/documentation/xpc/xpc_connection_set_event_handler(::) https://developer.apple.com/forums/thread/837286 (received-message checking versus initial outgoing delivery) An API reference, versioned contract, or explicit statement that either guarantee is unavailable would help determine the safe supported boundary. I am not requesting private APIs or a workaround that treats a caller assertion as authorization.
Replies
1
Boosts
0
Views
122
Activity
5d
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
629
Activity
1w
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
217
Activity
1w
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
321
Activity
1w
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
173
Activity
1w
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
129
Activity
1w
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
156
Activity
1w
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
101
Activity
2w
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
476
Activity
2w
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
301
Activity
2w
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
189
Activity
2w
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
272
Activity
3w