Service Management

RSS for tag

The Service Management framework provides facilities to load and unload launched services and read and modify launched dictionaries from within an application.

Posts under Service Management tag

200 Posts

Post

Replies

Boosts

Views

Activity

Service Management Resources
Service Management framework supports installing and uninstalling services, including Service Management login items, launchd agents, and launchd daemons. General: Forums subtopic: App & System Services > Processes & Concurrency Forums tag: Service Management Service Management framework documentation Daemons and Services Programming Guide archived documentation Technote 2083 Daemons and Agents — It hasn’t been updated in… well… decades, but it’s still remarkably relevant. EvenBetterAuthorizationSample sample code — This has been obviated by SMAppService. SMJobBless sample code — This has been obviated by SMAppService. Sandboxing with NSXPCConnection sample code WWDC 2022 Session 10096 What’s new in privacy introduces the new SMAppService facility, starting at 07˸07 BSD Privilege Escalation on macOS forums post Getting Started with SMAppService forums post Background items showing up with the wrong name forums post Related forums tags include: XPC, Apple’s preferred inter-process communication (IPC) mechanism Inter-process communication, for other IPC mechanisms Share and Enjoy — Quinn “The Eskimo!” @ Developer Technical Support @ Apple let myEmail = "eskimo" + "1" + "@" + "apple.com"
0
0
3.0k
Sep ’25
Sandboxed SMAppService LaunchDaemon: supported identity and persistent storage?
Technology: Service Management (SMAppService), App Sandbox, launchd, Foundation file URLs. This is a documentation/support question based on a standalone signed probe. It is not an assertion of a confirmed Apple defect, and it is not a duplicate of the launchd enhancement FB24726121 referenced in DTS thread 844906. Request Please clarify the supported identity and persistent-storage architecture for this combination of requirements. We need a sandboxed Mac App Store app to install its bundled, sandboxed SMAppService LaunchDaemon through one in-app action and the required native approval. The LAN listener must be unprivileged and remain available after logout and at boot. On macOS 27.2 beta 1 (26B5086k), our signed app-like probe launches and accesses its private container as the default root identity. We have read DTS thread 844906’s single-process privilege-drop guidance; this request concerns the additional sandbox, storage, and distribution limits. Observations • UserName=nobody exits during sandbox initialization with /var/empty home and secinitd UID errors. • An existing non-root account control also traps in libsecinit before main. • SessionCreate=true with that existing non-root account still terminates in libsecinit before main. • Creating a new audit session did not resolve sandbox initialization in this probe. • A retained directory descriptor works with openat after dropping privileges, but ordinary container paths and /dev/fd/directory/child do not. • All diagnostic registrations were removed for these tests; no product data or network listener was involved. Questions Is a sandboxed bootstrap that permanently drops groups, GID, and UID before opening a LAN listener a supported architecture for the Mac App Store distribution lane? How should such a LaunchDaemon obtain an isolated service identity and persistent container with Foundation/MLX-compatible file URLs without an external installer, shared writable storage, manual account/ACL setup, or unsupported sandbox exceptions? Please identify the supported public-API path, and clearly distinguish Service Management support from App Review guideline 2.4.5 constraints. If these requirements cannot be combined, please state which ones are mutually exclusive. Reference: https://developer.apple.com/forums/thread/844906 Expected outcome: documented guidance on a supported arrangement, or a clear statement of which requirements cannot be combined. We are withholding the product’s Release host installation until the identity/storage design is qualified.
2
0
105
2d
macOS 27 - my faceless bg-only app now appears in the Dock - how to get rid of that?
My macOS app Find Any File contains another app inside its Resources folder. It's a background-only app that checks if the user presses a hotkey, in which case it launches my app. Since macOS 27, when the hotkey app is running, it appears in the Dock with a "Running in Background" subtitle. That's totally not wanted. How do I make it not appear in the Dock? I've got both "LSBackgroundOnly" and "LSUIElement" set to true in the Info.plist, to no avail.
3
0
132
5d
[27.0beta] Wrong app shown as running in Background in Dock
I develop a tool on macOS which is composed of an UI app to manage the main app settings, and an Agent that runs in background doing some tasks ? (Running the agent is optional, can be launched from the UI app, and can be launched by macOS at startup with SMAppService. ) Agent has the LSUIElement flag set, and only shows a Menu Extra (or whatever it now named), and sometimes some notifications. The whole App package is bundled this way MainAppUI.app/Contents/Library/LoginItems/AppAgent.app (for SMAppService to work) This has been working correctly for years Now on macOS 27 beta, once I quit the UI App, having launched the Agent, the Dock reports the UI App is still running in background (with the grey dot) . But only the Agent is running, not the UI app process. Moreover, System Settings->Background apps reports both the UI app AND the Agent as both requesting to run in background. I would have expected only the Agent being listed in System Settings, and nothing appearing in the Dock. Is this a bug in the OS beta , showing the top-level container bundle as the app running in background instead of the executable direct container ? Or maybe it's on me and I should bundle my app differently ? (I cannot "reverse" the bundle and put the Agent as the main app, with UI "inside", as double clicking the main app should launch the UI App , not the Agent. ) BTW, filed FB23203848 for the same subject. thanks for any direction
3
1
1k
5d
Supported OS-owned lifetime for one-shot macOS work after its controller exits
I’m designing a macOS utility that needs to run a bounded, one-shot diagnostic and collect its result. The lifetime problem is: A controller asks for the diagnostic to start. The diagnostic may begin successfully. The controller can then fail immediately — potentially before it has retained the child’s PID or established output collection. The diagnostic may close stdin/stdout/stderr while continuing to run. The diagnostic must not become an unmanaged orphan if the controller disappears. A focused test case uses Foundation.Process: Controller launches Child. Controller immediately exits with _exit(42), without waiting for Child or retaining its process identifier. Child calls setsid(), closes stdin/stdout/stderr, stays alive for up to 120 seconds, then exits. What I’m trying to establish is the supported macOS lifecycle boundary, rather than inventing a cleanup scheme around PIDs. Is there a supported per-user launchd or other OS-managed mechanism where the OS assumes responsibility for the job before the diagnostic process can start, such that the requesting controller may subsequently fail without leaving an unmanaged process? Specifically: At what point does the OS own the lifetime relative to registration and process creation? What supported mechanism bounds or terminates the job if the requesting controller disappears? Is there a supported hard execution-time limit, rather than an idle-time concept? How are descendants or process groups contained, and does calling setsid() conflict with that containment? What completion or failure information remains available to a later controller after the original requester has died? Are there important per-user, privilege, sandboxing, signing, or macOS-version limitations? I’m not reporting an Apple bug and I’m not asking for a custom recovery implementation. I’m trying to identify the documented supported lifetime mechanism and its guarantees and limitations before choosing an architecture. Environment: macOS 26.6.2 Apple silicon Foundation.Process is used by the focused reproducer Apple Developer Technical Support suggested I start a new thread for this specific question in Processes & Concurrency.
4
0
203
1w
SMAppService LaunchDaemon: is privilege drop followed by same-PID exec supported before Mach service check-in?
I’m designing a least-privilege system LaunchDaemon registered with SMAppService, and I’d like to clarify whether the following architecture is supported by public macOS contracts. The LaunchDaemon declares a MachServices entry. Its steady-state service must run as a dedicated non-root account and later creates an NSXPCListener for that Mach service. We currently launch the daemon directly using UserName, GroupName, and InitGroups=false. However, InitGroups=false does not appear to guarantee that the resulting process supplementary-group list is limited to the service’s intended group. In testing, the daemon received a supplementary group outside our accepted set. We therefore do not want to depend on incidental inherited launch-time group state. We are considering this alternative: launchd starts a small, fixed, code-signed bootstrap executable as root. The bootstrap reads the target UID/GID from an existing protected root-owned binding record. It establishes an exact credential state using public BSD APIs, conceptually: setgroups(...) setgid(...) setuid(...) It verifies the resulting non-root credentials. It creates no XPC listener or storage connection while privileged. Without forking, it permanently replaces itself using execve() (or possibly POSIX_SPAWN_SETEXEC) with another fixed, separately signed executable in the same bundle. That non-root executable independently validates its security state and then creates NSXPCListener(machServiceName:) for the Mach service declared by the original LaunchDaemon job. The bootstrap would not remain as a privileged parent or supervisor. My main questions are: Is a same-PID exec after permanent UID/GID/supplementary-group reduction supported for an SMAppService system LaunchDaemon before it checks in to its declared Mach service? Does the exec-replaced process retain the launchd/bootstrap context required for NSXPCListener(machServiceName:) to check in to that Mach service? If so, what execution context must be preserved across exec (for example bootstrap context, environment, file descriptors, or Mach rights)? Is there a documented way to preserve only the context required for the LaunchDaemon/Mach-service relationship without carrying unintended root-derived capabilities into the non-root executable? Would SMAppService.unregister() / normal launchd termination continue to treat the exec-replaced process as the same LaunchDaemon job? If this topology is not supported, is there an Apple-supported way to establish an exact supplementary-group set before a non-root SMAppService LaunchDaemon begins handling its Mach service? The goal is to avoid relying on undocumented launchd behavior, incidental supplementary groups, private APIs, or a long-lived privileged helper. I’m specifically looking for the supported contract here rather than whether this happens to work on a particular macOS release.
4
0
359
2w
PrivilegedHelperTool no longer launches automatically after SMJobBless to SMAppService
In transitioning an existing privileged helper tool from SMJobBless to the new-ish SMAppService APIs, I ran into a problem. Registration via [SMAppService daemonServiceWithPlistName:...]; works and I get the green light via SMAppServiceStatusEnabled. Presumably that means my app’s bundle structure is correct, except that when my app creates a connection to the named mach service advertised by the helper tool, the helper tool process no longer launches on-demand. The client side (main app) uses: xpc_connection_create_mach_service("com.fxfactory.FxFactory.helper", queue, XPC_CONNECTION_MACH_SERVICE_PRIVILEGED); The listener / helper tool uses: xpc_connection_create_mach_service("com.fxfactory.FxFactory.helper", dispatch_get_main_queue(), XPC_CONNECTION_MACH_SERVICE_LISTENER); When installed via SMJobBless, the privileged helper tool would automatically launch when a connection attempt is made by the app. This no longer works. The app sits indefinitely, never receiving a reply on its otherwise "live" xpc_connection. The only useful hints on the Console seemed to be the following: taskgated-helper Checking profile: FxFactory Provisioning Profile 2026-1-15 taskgated-helper com.fxfactory.FxFactory.helper: Unsatisfied entitlements: com.apple.developer.service-management.managed-by-main-app taskgated-helper Disallowing: com.fxfactory.FxFactory.helper ...and: /Applications/FxFactory.app/Contents/MacOS/com.fxfactory.FxFactory.helper not valid: Error Domain=AppleMobileFileIntegrityError Code=-413 "No matching profile found" UserInfo={NSURL=file:///Applications/FxFactory.app/Contents/MacOS/com.fxfactory.FxFactory.helper, unsatisfiedEntitlements=<CFArray 0x7b94c33a40 [0x200d1aab0]>{type = immutable, count = 1, values = ( 0 : <CFString 0x7b950305a0 [0x200d1aab0]>{contents = "com.apple.developer.service-management.managed-by-main-app"} )}, NSLocalizedDescription=No matching profile found} I'm testing this on macOS 27 Beta, not sure if that would/should make a difference. LLMs give a ton of contradicting advice on this topic. I would be great to clear some things out: In addition to having the launchd plist that describes the helper tool copied to /Contents/Library/LaunchDaemons, should the same plist also be embedded by the helper tool binary via -sectcreate __TEXT __launchd_plist? Is it true that XPC_CONNECTION_MACH_SERVICE_PRIVILEGED should be omitted from the client, when using the new SMAppService API? (the LLM surely insisted on this point, but passing 0 didn't fix anything.) What are the unsatisfied requirements of the com.apple.developer.service-management.managed-by-main-app that taskgated is referring to? Again LLMs insist that there are no additional requirements beyond code-signing by the same team, but this must be false. Could it be that helper tool needs to use the same provisioning profile as the main app? Could it be that it needs its own, tied to its own bundle ID? Here are the entitlements on the helper tool sitting in the /Contents/MacOS/ directory of the app bundle, presumably the result of the build process injecting them into their own __TEXT section, similarly to how one would inject __launchd_plist: [Dict] [Key] com.apple.developer.service-management.managed-by-main-app [Value] [Bool] true [Key] com.apple.security.app-sandbox [Value] [Bool] false [Key] com.apple.security.get-task-allow [Value] [Bool] true Assuming that my privileged helper tool is not launching simply because my bundle is violating the requirements for the com.apple.developer.service-management.managed-by-main-app entitlement, what exactly are these requirements? As a side question: if one needs these LaunchDaemons to perform some actions with root privileges, what exactly would enabling the App Sandbox (com.apple.security.app-sandbox = true) on the privileged helper tool accomplish? Is there any point in confining a process with root privileges inside a container? Thank you!
6
0
677
3w
Is it possible to run macOS VM (Virtualization API) under a launchd daemon?
Hi, I was trying to run a macOS VM under a launchd daemon as part of a requirement. The parent daemon spawns a macOS VM under root user. Sometimes this is fine, but sometimes I'm getting a security error from VZ library : Unable to access security information. The virtual machine encountered a security error. In system logs, I was able to see this : ctkd: unable to generate key: error e00002e2 for com.apple.Virtualization.VirtualMachine with SepKey ACL I think this indicates Virtualization.framework asked CryptoTokenKit/Secure Enclave to create a key, and the security subsystem rejected it in the current execution context. Is it possible to run VM this way ? If yes, what am I missing ?
1
0
582
Aug ’26
Updating a user’s login keychain after a password change
Hi, We are looking for guidance on synchronizing a user’s login keychain passphrase after changing that user’s local account password, when the user is not currently logged in. Context We have an MDM product for macOS, and we sometimes need to change a local account password while that user is not logged in. Updating the account password itself from our privileged daemon is fine. The hard part is keeping their login keychain in sync — that only seems to work when we run as that user, in their own session. So we perform the keychain update from a per-user LaunchAgent, not from root. What works (user is logged in) From the user’s LaunchAgent we run: # 1) Change account password (if not already changed) dscl . -passwd "/Users/<username>" "<currentPassword>" "<newPassword>" # 2) Sync login keychain passphrase security set-keychain-password -o "<currentPassword>" -p "<newPassword>" login.keychain-db With correct current/new secrets, this succeeds when the helper is running as that user while they are logged in. What fails (user is not logged in) Starting the same LaunchAgent for that user fails with: Bootstrap failed: 125: Domain does not support specified action So we cannot get user-context execution for the keychain update while the user is not logged in. Approaches we already tried Post-login LaunchAgent — We stage the current/new passwords and install a LaunchAgent that runs after the user logs in to migrate the keychain. By the time the user is logged in and the agent runs, macOS has already created a new login keychain and renamed the previous one (e.g. login.keychain-db-renamed-N). At that point we can no longer reliably migrate/restore the original keychain. sudo -u <username> security set-keychain-password … from a root daemon — Led to Keychain Access / keychain state corruption in our testing; we do not consider this a production path. Delete the login keychain — Works as a reset, but discards saved credentials. Acceptable for some admin reset flows; not acceptable for a password change where we know both secrets and want to preserve the keychain. Ask Is there a supported way to update login.keychain-db for a user who is not logged in, given known current and new passphrases, without deleting the keychain? If so, what is that way? If not is there a way to merge the old login keychain as we have the old password too? Also please confirm whether updating another user’s login keychain from root / sudo -u is unsupported, so we can exclude it from product design. Happy to provide sanitized logs (error 125, security failures, renamed keychain timelines) if useful. Thanks.
1
0
625
Aug ’26
CLLocationManager stuck at notDetermined in a signed LaunchAgent on macOS 14
Environment macOS 14+ (Sonoma), Apple Silicon Background LaunchAgent installed at /Applications/.app, launched by a plist in /Library/LaunchAgents. LSUIElement = true (no Dock icon). Signed with a Developer ID Application certificate, hardened runtime, secure timestamp. Notarized. No provisioning profile embedded. Distributed outside the App Store (signed .pkg installer). Info.plist keys present in the installed bundle: NSLocationUsageDescription NSLocationWhenInUseUsageDescription NSLocationAlwaysAndWhenInUseUsageDescription Entitlements file: empty (I removed com.apple.developer.* entitlements because they require a provisioning profile that Developer ID distribution cannot ship.) What I need CoreWLAN's scanForNetworks(withSSID:) returns entries with nil ssid / nil bssid on macOS 14+ unless the process has Location authorization. I'm trying to obtain that authorization from the LaunchAgent so I can populate SSID/BSSID for a connectivity report. What I'm doing Instantiating CLLocationManager on the main thread (verified via Thread.isMainThread) from an NSApplication.shared.run() runloop. Setting a CLLocationManagerDelegate. Calling requestWhenInUseAuthorization(), requestAlwaysAuthorization(), and startUpdatingLocation(). Observed behavior No authorization prompt is ever displayed. authorizationStatus stays at .notDetermined across launches. locationManager(_:didFailWithError:) fires with kCLErrorDomain error 1 (kCLErrorDenied). System Settings → Privacy & Security → Location Services lists the app and its toggle can be flipped ON, yet the process still reads authorizationStatus == .notDetermined immediately after and on subsequent launches. locationd logs (Console) around the same time show: "#Warning #ClientResolution the passed keyPath is not registered. Resolving to #nullCKP" Things I've already tried Verified Info.plist keys are embedded in the installed bundle (defaults read /Applications/<app>/Contents/Info.plist). Verified codesign is valid and entitlements are preserved on install (codesign -d --entitlements - /Applications/<app>). tccutil reset All <bundle-id> and full reboot. Uninstall + reinstall. Toggling Location Services OFF and back ON, both globally and per-app. Ensuring all CLLocationManager interaction runs on the main thread. Verified CLLocationManager.locationServicesEnabled() returns true. Questions Is a Developer-ID-signed LaunchAgent (LSUIElement=true, no Dock icon) supposed to be able to trigger the standard Location prompt on macOS 14+, or is a foreground/UI process required to establish initial authorization? What does the locationd "keyPath is not registered / Resolving to #nullCKP" message indicate, and how do I diagnose which registration is missing? Is there an entitlement or Info.plist key I'm still missing for Developer-ID-distributed background agents to be recognized by locationd? Given that the Settings toggle appears to be ON but authorizationStatus still reports .notDetermined to the running process, is there a bundle identity / code-signing check I can run to confirm locationd is looking at the same identity Settings is showing? Any pointers appreciated - happy to share codesign output, sample entitlements plist, or the full locationd log excerpt on request.
2
0
565
Aug ’26
Mac app automatic cloud sync even when app is cloud
My scenario I have an app which stores data using SwiftData / CloudKit automatic sync It works as expected on iOS, sync happens even when the app is closed. On Mac, when mac app is closed the data from the CloudKit is not pulled into the DB. It would be nice if the widget on the Mac is updated even when the Mac app is closed. Like from a sync from an iPhone. My problem: I don't do anything for sync other than just initializing the ModelContainer and everything is taken care of. The local store has its own system level tables to maintain the sync states. So I am a bit hesitant to do a separate sync in the background process (LoginItem / LaunchAgent / LaunchDaemon. I need to read a lot on this because I am just beginning to explore this part Questions Is it feasible / advisable to have one instance of the ModelContainer created in the background process and access it in the main app for the Mac? Reason for asking is because ModelContainer is the one that does all the sync magically. Or is this too much of an overhead and users can open the app to keep the widget updated?
0
0
704
Jul ’26
Sandboxed App <> Launch Agent - how to communicate?
I’m building a sandboxed macOS App Store app that registers an agent using SMAppService. I’m trying to understand the IPC setup between the main app and the SMAppService-managed agent. The obvious options seem to be: XPC with a Mach service But from what I understand, I’d need a special entitlement that allows me to communicate over XPC Mach service - which is unlikely to pass Mac App Store review. So how do people communicate with processes registered with SMAppService?
2
0
1.2k
Jun ’26
Unable to enable login helper
I have one report from a customer, who migrated all data from his old MacBook to a new one. His is on Tahoe 26.5.1 (25F80). Here is my relevant code: + (BOOL)enableLoginItem:(BOOL)enable { NSOperatingSystemVersion osv = NSProcessInfo.processInfo.operatingSystemVersion; if (osv.majorVersion >= 13) { NSError* error; SMAppService* service = [SMAppService loginItemServiceWithIdentifier:MY_HELPER_APP_ID]; if (![service registerAndReturnError:&error] && error) @throw error; return YES; } return SMLoginItemSetEnabled((__bridge CFStringRef)MY_HELPER_APP_ID, enable); } What should I do to re-enable the login helper?
2
0
1.2k
Jun ’26
Can SMAppService Daemon replace SMJobBless for exclusive HID capture from keyboards?
To gain exclusive access to keyboard HID devices like Amazon Fire Bluetooth remote controls, my app has been installing a privileged helper tool with SMJobBless in the past. The app - which also has Accessibility permissions - then invoked and communicated with that helper tool through XPC. Now I'm looking into replacing that with a daemon installed through the newer SMAppService APIs, but running into a permission problem: If I try to exclusively open a keyboard HID device from the SMAppService-registered XPC service/daemon (which runs as root as seen in Activity Monitor), IOHIDDeviceOpen returns kIOReturnNotPermitted. I've spent many hours now trying to get it to work, but so far didn't find a solution. Could it be that XPC services registered as a daemon through SMAppService do not inherit the TCC permissions from the invoking process (here: Accessibility permissions) - and the exclusive IOHIDDeviceOpen therefore fails?
9
0
1k
Jun ’26
SMAppService - helper is not started
My software installs a privileged daemon using the SMAppService api. After removing the executables and recompiling the software I sometimes find that it needs to be registered again. After doing this, i.e. ensuring the application is properly registered and enabled in Login Items & Extensions the helper is not run when initiated from XPC. SMAppService.status has returned .enabled, and there is a valid job dictionary for the helper. I check the job dictionary with a function called updatePenaltyBoxStatus() that was given to me by a friend but I think originated from Apple. If I logoff (or reboot), login again, manually open Login Items & Extensions to check registration, then retry the application, it works. I don't mind doing this but it is probably a bit much for a lot of my users. Is there a reliable way to do this programatically? Here is my Swift translation of updatePenaltyBoxStatus. I fetch the job dictionary with SMJobCopyDictionary() prior to calling isInPenaltyBox(). I also had to write C wrapper functions for the WIFEXITED and WIFEXITSTATUS macros. func isInPenaltyBox(_ dict: Dictionary<String, Any>?) -> Bool { guard let jobDict = dict else { // If the helper was in the penalty box, unregistering it doesn't change that. So don't override a previous helperInPenaltyBox value return m_penalty_box } if let lastExitStatusObj = jobDict["LastExitStatus"] as? NSNumber { let lastExitStatus = lastExitStatusObj.intValue if wifexited(Int32(lastExitStatus)) == 0 { // It might've stopped or exited due to a signal or whatever. // Regardless, it didn't meet our criteria for winding up in the penalty box. m_penalty_box = false } // Now get the exit status and check for `EX_CONFIG`. let status = wexitstatus(Int32(lastExitStatus)) let newInPenaltyBox = status == EX_CONFIG if m_penalty_box != newInPenaltyBox { Logger.instance.log( "Penalty box change: " + m_ident + " old: " + String(m_penalty_box) + " new: " + String(newInPenaltyBox)) } m_penalty_box = newInPenaltyBox } return m_penalty_box }
2
0
1.1k
May ’26
SMAppService.daemon and AirWatch installation
My enterprise app requires a launch daemon that provides services to support my Security agent plugin. I bundle everything in an App and install using AirWatch. This all used to work until something changed, either AirWatch or the MacOS version. Now the install fails because my SMAppService instance returns an error when .register is called: Error Domain=SMAppServiceErrorDomain Code=1 "Operation not permitted" UserInfo={NSLocalizedFailureReason=Operation not permitted} If I install by opening my installer package as a user, the install always succeeds. The app is an enterprise app and is not distributed through the App Store. The app also installs a security extension. The security extension is installed and activated before any calls to SMAppService. I can't figure out what has changed in the last few months that would cause the error, or how to fix this. Any help or pointers would be appreciated.
6
0
590
Apr ’26
How to modify the launchctl config to start Postfix?
On Sequoia, I want to configure my postfix as a server. And for this I have to change the way postfix is started from: /System/Library/LaunchDaemons/com.apple.postfix.master.plist But this file is on the read only / file system. Then I just unloaded this startup, and made a new one in: /Library/LaunchDaemons/com.apple.postfix.master.plist and I was able to start it. But on the next system boot, the system one in /System/Library/LaunchDaemons was started again. How should I cleanly and permanently achieve this server basic modification?
3
0
528
Mar ’26
Securing XPC Daemon Communication from Authorization Plugin
I'm working on securing communication between an Authorization Plugin and an XPC daemon, and I’d appreciate some guidance on best practices and troubleshooting. The current design which, I’ve implemented a custom Authorization Plugin for step-up authentication, which is loaded by Authorization Services at the loginwindow (inside SecurityAgent). This plugin acts as an XPC client and connects to a custom XPC daemon. Setup Details 1. XPC Daemon Runs as root (LaunchDaemon) Not sandboxed (my understanding is that root daemons typically don’t run sandboxed—please correct me if this is wrong) Mach service: com.roboInc.AuthXpcDaemon Bundle identifier: com.roboInc.OfflineAuthXpcDaemon 2. Authorization Plugin Bundle identifier: com.roboInc.AuthPlugin Loaded by SecurityAgent during login 3. Code Signing Both plugin and daemon are signed using a development certificate What I’m Trying to Achieve I want to secure the XPC communication so that: The daemon only accepts connections from trusted clients The plugin only connects to the legitimate daemon Communication is protected against unauthorized access The Issue I'm facing I attempted to validate code signatures using: SecRequirementCreateWithString SecCodeCopyGuestWithAttributes SecCodeCheckValidity However, validation consistently fails with: -67050 (errSecCSReqFailed) Could you please help here What is the recommended way to securely authenticate an Authorization Plugin (running inside SecurityAgent) to a privileged XPC daemon? Since the plugin runs inside SecurityAgent, how can the daemon reliably distinguish my plugin from other plugins? What is the correct approach to building a SecRequirement in this scenario? Any guidance, examples, or pointers would be greatly appreciated. Thanks in advance!
6
0
1.6k
Mar ’26
libswiftCompatibilitySpan.dylib missing in XCode 26.3
A macOS privileged helper tool that uses SubProcess crashes on intel Macs (running macOS 13 - 15: unable to test on macOS 26 on intel) with the error that libswiftCompatibilitySpan.dylib cannot be loaded when built with XCode 26.3. The same helper tool works as expected with XCode 26.2. The helper is installed using SMAppService. When I remove the dependency for SubProcess, the crash no longer occurs (but important functionality is also disabled).
9
0
764
Mar ’26
LaunchAgent (Mac) as peripheral doesn't show a pairing request.
The same code built in a regular Mac app (with UI) does get paired. The characteristic properties are [.read, .write, .notify, .notifyEncryptionRequired] The characteristic permissions are [.readEncryptionRequired, .writeEncryptionRequired] My service is primary. In the iOS app (central) I try to read the characteristic, but an error is reported: Error code: 5, Description: Authentication is insufficient.
9
0
1.9k
Mar ’26
Migrating away from SMJobBless
I have migrated my code to use SMAppService but am running into trouble deleting the old SMJobBless launchd registration using launchd remove. I am invoking this from a root shell when I detect the daemon and associated plist still exist, then also deleting those files. The remove seems to work (i.e. no errors returned) but launchd list shows the service is registered, with a status code of 28 I am using the same label for SMAppService as previously and suspect this is the reason for the problem. However, I am reluctant to change the label as there will a lot of code changes to do this. If I quit my application, disable the background job in System Settings and run sudo launchd remove in the Terminal then it is removed and my application runs as expected once the background job is re-enabled. Alternatively, a reboot seems to get things going. Any suggestions on to how I could do this more effectively welcome.
2
0
930
Mar ’26
Service Management Resources
Service Management framework supports installing and uninstalling services, including Service Management login items, launchd agents, and launchd daemons. General: Forums subtopic: App & System Services > Processes & Concurrency Forums tag: Service Management Service Management framework documentation Daemons and Services Programming Guide archived documentation Technote 2083 Daemons and Agents — It hasn’t been updated in… well… decades, but it’s still remarkably relevant. EvenBetterAuthorizationSample sample code — This has been obviated by SMAppService. SMJobBless sample code — This has been obviated by SMAppService. Sandboxing with NSXPCConnection sample code WWDC 2022 Session 10096 What’s new in privacy introduces the new SMAppService facility, starting at 07˸07 BSD Privilege Escalation on macOS forums post Getting Started with SMAppService forums post Background items showing up with the wrong name forums post Related forums tags include: XPC, Apple’s preferred inter-process communication (IPC) mechanism Inter-process communication, for other IPC mechanisms Share and Enjoy — Quinn “The Eskimo!” @ Developer Technical Support @ Apple let myEmail = "eskimo" + "1" + "@" + "apple.com"
Replies
0
Boosts
0
Views
3.0k
Activity
Sep ’25
Sandboxed SMAppService LaunchDaemon: supported identity and persistent storage?
Technology: Service Management (SMAppService), App Sandbox, launchd, Foundation file URLs. This is a documentation/support question based on a standalone signed probe. It is not an assertion of a confirmed Apple defect, and it is not a duplicate of the launchd enhancement FB24726121 referenced in DTS thread 844906. Request Please clarify the supported identity and persistent-storage architecture for this combination of requirements. We need a sandboxed Mac App Store app to install its bundled, sandboxed SMAppService LaunchDaemon through one in-app action and the required native approval. The LAN listener must be unprivileged and remain available after logout and at boot. On macOS 27.2 beta 1 (26B5086k), our signed app-like probe launches and accesses its private container as the default root identity. We have read DTS thread 844906’s single-process privilege-drop guidance; this request concerns the additional sandbox, storage, and distribution limits. Observations • UserName=nobody exits during sandbox initialization with /var/empty home and secinitd UID errors. • An existing non-root account control also traps in libsecinit before main. • SessionCreate=true with that existing non-root account still terminates in libsecinit before main. • Creating a new audit session did not resolve sandbox initialization in this probe. • A retained directory descriptor works with openat after dropping privileges, but ordinary container paths and /dev/fd/directory/child do not. • All diagnostic registrations were removed for these tests; no product data or network listener was involved. Questions Is a sandboxed bootstrap that permanently drops groups, GID, and UID before opening a LAN listener a supported architecture for the Mac App Store distribution lane? How should such a LaunchDaemon obtain an isolated service identity and persistent container with Foundation/MLX-compatible file URLs without an external installer, shared writable storage, manual account/ACL setup, or unsupported sandbox exceptions? Please identify the supported public-API path, and clearly distinguish Service Management support from App Review guideline 2.4.5 constraints. If these requirements cannot be combined, please state which ones are mutually exclusive. Reference: https://developer.apple.com/forums/thread/844906 Expected outcome: documented guidance on a supported arrangement, or a clear statement of which requirements cannot be combined. We are withholding the product’s Release host installation until the identity/storage design is qualified.
Replies
2
Boosts
0
Views
105
Activity
2d
macOS 27 - my faceless bg-only app now appears in the Dock - how to get rid of that?
My macOS app Find Any File contains another app inside its Resources folder. It's a background-only app that checks if the user presses a hotkey, in which case it launches my app. Since macOS 27, when the hotkey app is running, it appears in the Dock with a "Running in Background" subtitle. That's totally not wanted. How do I make it not appear in the Dock? I've got both "LSBackgroundOnly" and "LSUIElement" set to true in the Info.plist, to no avail.
Replies
3
Boosts
0
Views
132
Activity
5d
[27.0beta] Wrong app shown as running in Background in Dock
I develop a tool on macOS which is composed of an UI app to manage the main app settings, and an Agent that runs in background doing some tasks ? (Running the agent is optional, can be launched from the UI app, and can be launched by macOS at startup with SMAppService. ) Agent has the LSUIElement flag set, and only shows a Menu Extra (or whatever it now named), and sometimes some notifications. The whole App package is bundled this way MainAppUI.app/Contents/Library/LoginItems/AppAgent.app (for SMAppService to work) This has been working correctly for years Now on macOS 27 beta, once I quit the UI App, having launched the Agent, the Dock reports the UI App is still running in background (with the grey dot) . But only the Agent is running, not the UI app process. Moreover, System Settings->Background apps reports both the UI app AND the Agent as both requesting to run in background. I would have expected only the Agent being listed in System Settings, and nothing appearing in the Dock. Is this a bug in the OS beta , showing the top-level container bundle as the app running in background instead of the executable direct container ? Or maybe it's on me and I should bundle my app differently ? (I cannot "reverse" the bundle and put the Agent as the main app, with UI "inside", as double clicking the main app should launch the UI App , not the Agent. ) BTW, filed FB23203848 for the same subject. thanks for any direction
Replies
3
Boosts
1
Views
1k
Activity
5d
Supported OS-owned lifetime for one-shot macOS work after its controller exits
I’m designing a macOS utility that needs to run a bounded, one-shot diagnostic and collect its result. The lifetime problem is: A controller asks for the diagnostic to start. The diagnostic may begin successfully. The controller can then fail immediately — potentially before it has retained the child’s PID or established output collection. The diagnostic may close stdin/stdout/stderr while continuing to run. The diagnostic must not become an unmanaged orphan if the controller disappears. A focused test case uses Foundation.Process: Controller launches Child. Controller immediately exits with _exit(42), without waiting for Child or retaining its process identifier. Child calls setsid(), closes stdin/stdout/stderr, stays alive for up to 120 seconds, then exits. What I’m trying to establish is the supported macOS lifecycle boundary, rather than inventing a cleanup scheme around PIDs. Is there a supported per-user launchd or other OS-managed mechanism where the OS assumes responsibility for the job before the diagnostic process can start, such that the requesting controller may subsequently fail without leaving an unmanaged process? Specifically: At what point does the OS own the lifetime relative to registration and process creation? What supported mechanism bounds or terminates the job if the requesting controller disappears? Is there a supported hard execution-time limit, rather than an idle-time concept? How are descendants or process groups contained, and does calling setsid() conflict with that containment? What completion or failure information remains available to a later controller after the original requester has died? Are there important per-user, privilege, sandboxing, signing, or macOS-version limitations? I’m not reporting an Apple bug and I’m not asking for a custom recovery implementation. I’m trying to identify the documented supported lifetime mechanism and its guarantees and limitations before choosing an architecture. Environment: macOS 26.6.2 Apple silicon Foundation.Process is used by the focused reproducer Apple Developer Technical Support suggested I start a new thread for this specific question in Processes & Concurrency.
Replies
4
Boosts
0
Views
203
Activity
1w
SMAppService LaunchDaemon: is privilege drop followed by same-PID exec supported before Mach service check-in?
I’m designing a least-privilege system LaunchDaemon registered with SMAppService, and I’d like to clarify whether the following architecture is supported by public macOS contracts. The LaunchDaemon declares a MachServices entry. Its steady-state service must run as a dedicated non-root account and later creates an NSXPCListener for that Mach service. We currently launch the daemon directly using UserName, GroupName, and InitGroups=false. However, InitGroups=false does not appear to guarantee that the resulting process supplementary-group list is limited to the service’s intended group. In testing, the daemon received a supplementary group outside our accepted set. We therefore do not want to depend on incidental inherited launch-time group state. We are considering this alternative: launchd starts a small, fixed, code-signed bootstrap executable as root. The bootstrap reads the target UID/GID from an existing protected root-owned binding record. It establishes an exact credential state using public BSD APIs, conceptually: setgroups(...) setgid(...) setuid(...) It verifies the resulting non-root credentials. It creates no XPC listener or storage connection while privileged. Without forking, it permanently replaces itself using execve() (or possibly POSIX_SPAWN_SETEXEC) with another fixed, separately signed executable in the same bundle. That non-root executable independently validates its security state and then creates NSXPCListener(machServiceName:) for the Mach service declared by the original LaunchDaemon job. The bootstrap would not remain as a privileged parent or supervisor. My main questions are: Is a same-PID exec after permanent UID/GID/supplementary-group reduction supported for an SMAppService system LaunchDaemon before it checks in to its declared Mach service? Does the exec-replaced process retain the launchd/bootstrap context required for NSXPCListener(machServiceName:) to check in to that Mach service? If so, what execution context must be preserved across exec (for example bootstrap context, environment, file descriptors, or Mach rights)? Is there a documented way to preserve only the context required for the LaunchDaemon/Mach-service relationship without carrying unintended root-derived capabilities into the non-root executable? Would SMAppService.unregister() / normal launchd termination continue to treat the exec-replaced process as the same LaunchDaemon job? If this topology is not supported, is there an Apple-supported way to establish an exact supplementary-group set before a non-root SMAppService LaunchDaemon begins handling its Mach service? The goal is to avoid relying on undocumented launchd behavior, incidental supplementary groups, private APIs, or a long-lived privileged helper. I’m specifically looking for the supported contract here rather than whether this happens to work on a particular macOS release.
Replies
4
Boosts
0
Views
359
Activity
2w
PrivilegedHelperTool no longer launches automatically after SMJobBless to SMAppService
In transitioning an existing privileged helper tool from SMJobBless to the new-ish SMAppService APIs, I ran into a problem. Registration via [SMAppService daemonServiceWithPlistName:...]; works and I get the green light via SMAppServiceStatusEnabled. Presumably that means my app’s bundle structure is correct, except that when my app creates a connection to the named mach service advertised by the helper tool, the helper tool process no longer launches on-demand. The client side (main app) uses: xpc_connection_create_mach_service("com.fxfactory.FxFactory.helper", queue, XPC_CONNECTION_MACH_SERVICE_PRIVILEGED); The listener / helper tool uses: xpc_connection_create_mach_service("com.fxfactory.FxFactory.helper", dispatch_get_main_queue(), XPC_CONNECTION_MACH_SERVICE_LISTENER); When installed via SMJobBless, the privileged helper tool would automatically launch when a connection attempt is made by the app. This no longer works. The app sits indefinitely, never receiving a reply on its otherwise "live" xpc_connection. The only useful hints on the Console seemed to be the following: taskgated-helper Checking profile: FxFactory Provisioning Profile 2026-1-15 taskgated-helper com.fxfactory.FxFactory.helper: Unsatisfied entitlements: com.apple.developer.service-management.managed-by-main-app taskgated-helper Disallowing: com.fxfactory.FxFactory.helper ...and: /Applications/FxFactory.app/Contents/MacOS/com.fxfactory.FxFactory.helper not valid: Error Domain=AppleMobileFileIntegrityError Code=-413 "No matching profile found" UserInfo={NSURL=file:///Applications/FxFactory.app/Contents/MacOS/com.fxfactory.FxFactory.helper, unsatisfiedEntitlements=<CFArray 0x7b94c33a40 [0x200d1aab0]>{type = immutable, count = 1, values = ( 0 : <CFString 0x7b950305a0 [0x200d1aab0]>{contents = "com.apple.developer.service-management.managed-by-main-app"} )}, NSLocalizedDescription=No matching profile found} I'm testing this on macOS 27 Beta, not sure if that would/should make a difference. LLMs give a ton of contradicting advice on this topic. I would be great to clear some things out: In addition to having the launchd plist that describes the helper tool copied to /Contents/Library/LaunchDaemons, should the same plist also be embedded by the helper tool binary via -sectcreate __TEXT __launchd_plist? Is it true that XPC_CONNECTION_MACH_SERVICE_PRIVILEGED should be omitted from the client, when using the new SMAppService API? (the LLM surely insisted on this point, but passing 0 didn't fix anything.) What are the unsatisfied requirements of the com.apple.developer.service-management.managed-by-main-app that taskgated is referring to? Again LLMs insist that there are no additional requirements beyond code-signing by the same team, but this must be false. Could it be that helper tool needs to use the same provisioning profile as the main app? Could it be that it needs its own, tied to its own bundle ID? Here are the entitlements on the helper tool sitting in the /Contents/MacOS/ directory of the app bundle, presumably the result of the build process injecting them into their own __TEXT section, similarly to how one would inject __launchd_plist: [Dict] [Key] com.apple.developer.service-management.managed-by-main-app [Value] [Bool] true [Key] com.apple.security.app-sandbox [Value] [Bool] false [Key] com.apple.security.get-task-allow [Value] [Bool] true Assuming that my privileged helper tool is not launching simply because my bundle is violating the requirements for the com.apple.developer.service-management.managed-by-main-app entitlement, what exactly are these requirements? As a side question: if one needs these LaunchDaemons to perform some actions with root privileges, what exactly would enabling the App Sandbox (com.apple.security.app-sandbox = true) on the privileged helper tool accomplish? Is there any point in confining a process with root privileges inside a container? Thank you!
Replies
6
Boosts
0
Views
677
Activity
3w
Is it possible to run macOS VM (Virtualization API) under a launchd daemon?
Hi, I was trying to run a macOS VM under a launchd daemon as part of a requirement. The parent daemon spawns a macOS VM under root user. Sometimes this is fine, but sometimes I'm getting a security error from VZ library : Unable to access security information. The virtual machine encountered a security error. In system logs, I was able to see this : ctkd: unable to generate key: error e00002e2 for com.apple.Virtualization.VirtualMachine with SepKey ACL I think this indicates Virtualization.framework asked CryptoTokenKit/Secure Enclave to create a key, and the security subsystem rejected it in the current execution context. Is it possible to run VM this way ? If yes, what am I missing ?
Replies
1
Boosts
0
Views
582
Activity
Aug ’26
Updating a user’s login keychain after a password change
Hi, We are looking for guidance on synchronizing a user’s login keychain passphrase after changing that user’s local account password, when the user is not currently logged in. Context We have an MDM product for macOS, and we sometimes need to change a local account password while that user is not logged in. Updating the account password itself from our privileged daemon is fine. The hard part is keeping their login keychain in sync — that only seems to work when we run as that user, in their own session. So we perform the keychain update from a per-user LaunchAgent, not from root. What works (user is logged in) From the user’s LaunchAgent we run: # 1) Change account password (if not already changed) dscl . -passwd "/Users/<username>" "<currentPassword>" "<newPassword>" # 2) Sync login keychain passphrase security set-keychain-password -o "<currentPassword>" -p "<newPassword>" login.keychain-db With correct current/new secrets, this succeeds when the helper is running as that user while they are logged in. What fails (user is not logged in) Starting the same LaunchAgent for that user fails with: Bootstrap failed: 125: Domain does not support specified action So we cannot get user-context execution for the keychain update while the user is not logged in. Approaches we already tried Post-login LaunchAgent — We stage the current/new passwords and install a LaunchAgent that runs after the user logs in to migrate the keychain. By the time the user is logged in and the agent runs, macOS has already created a new login keychain and renamed the previous one (e.g. login.keychain-db-renamed-N). At that point we can no longer reliably migrate/restore the original keychain. sudo -u <username> security set-keychain-password … from a root daemon — Led to Keychain Access / keychain state corruption in our testing; we do not consider this a production path. Delete the login keychain — Works as a reset, but discards saved credentials. Acceptable for some admin reset flows; not acceptable for a password change where we know both secrets and want to preserve the keychain. Ask Is there a supported way to update login.keychain-db for a user who is not logged in, given known current and new passphrases, without deleting the keychain? If so, what is that way? If not is there a way to merge the old login keychain as we have the old password too? Also please confirm whether updating another user’s login keychain from root / sudo -u is unsupported, so we can exclude it from product design. Happy to provide sanitized logs (error 125, security failures, renamed keychain timelines) if useful. Thanks.
Replies
1
Boosts
0
Views
625
Activity
Aug ’26
CLLocationManager stuck at notDetermined in a signed LaunchAgent on macOS 14
Environment macOS 14+ (Sonoma), Apple Silicon Background LaunchAgent installed at /Applications/.app, launched by a plist in /Library/LaunchAgents. LSUIElement = true (no Dock icon). Signed with a Developer ID Application certificate, hardened runtime, secure timestamp. Notarized. No provisioning profile embedded. Distributed outside the App Store (signed .pkg installer). Info.plist keys present in the installed bundle: NSLocationUsageDescription NSLocationWhenInUseUsageDescription NSLocationAlwaysAndWhenInUseUsageDescription Entitlements file: empty (I removed com.apple.developer.* entitlements because they require a provisioning profile that Developer ID distribution cannot ship.) What I need CoreWLAN's scanForNetworks(withSSID:) returns entries with nil ssid / nil bssid on macOS 14+ unless the process has Location authorization. I'm trying to obtain that authorization from the LaunchAgent so I can populate SSID/BSSID for a connectivity report. What I'm doing Instantiating CLLocationManager on the main thread (verified via Thread.isMainThread) from an NSApplication.shared.run() runloop. Setting a CLLocationManagerDelegate. Calling requestWhenInUseAuthorization(), requestAlwaysAuthorization(), and startUpdatingLocation(). Observed behavior No authorization prompt is ever displayed. authorizationStatus stays at .notDetermined across launches. locationManager(_:didFailWithError:) fires with kCLErrorDomain error 1 (kCLErrorDenied). System Settings → Privacy & Security → Location Services lists the app and its toggle can be flipped ON, yet the process still reads authorizationStatus == .notDetermined immediately after and on subsequent launches. locationd logs (Console) around the same time show: "#Warning #ClientResolution the passed keyPath is not registered. Resolving to #nullCKP" Things I've already tried Verified Info.plist keys are embedded in the installed bundle (defaults read /Applications/<app>/Contents/Info.plist). Verified codesign is valid and entitlements are preserved on install (codesign -d --entitlements - /Applications/<app>). tccutil reset All <bundle-id> and full reboot. Uninstall + reinstall. Toggling Location Services OFF and back ON, both globally and per-app. Ensuring all CLLocationManager interaction runs on the main thread. Verified CLLocationManager.locationServicesEnabled() returns true. Questions Is a Developer-ID-signed LaunchAgent (LSUIElement=true, no Dock icon) supposed to be able to trigger the standard Location prompt on macOS 14+, or is a foreground/UI process required to establish initial authorization? What does the locationd "keyPath is not registered / Resolving to #nullCKP" message indicate, and how do I diagnose which registration is missing? Is there an entitlement or Info.plist key I'm still missing for Developer-ID-distributed background agents to be recognized by locationd? Given that the Settings toggle appears to be ON but authorizationStatus still reports .notDetermined to the running process, is there a bundle identity / code-signing check I can run to confirm locationd is looking at the same identity Settings is showing? Any pointers appreciated - happy to share codesign output, sample entitlements plist, or the full locationd log excerpt on request.
Replies
2
Boosts
0
Views
565
Activity
Aug ’26
Mac app automatic cloud sync even when app is cloud
My scenario I have an app which stores data using SwiftData / CloudKit automatic sync It works as expected on iOS, sync happens even when the app is closed. On Mac, when mac app is closed the data from the CloudKit is not pulled into the DB. It would be nice if the widget on the Mac is updated even when the Mac app is closed. Like from a sync from an iPhone. My problem: I don't do anything for sync other than just initializing the ModelContainer and everything is taken care of. The local store has its own system level tables to maintain the sync states. So I am a bit hesitant to do a separate sync in the background process (LoginItem / LaunchAgent / LaunchDaemon. I need to read a lot on this because I am just beginning to explore this part Questions Is it feasible / advisable to have one instance of the ModelContainer created in the background process and access it in the main app for the Mac? Reason for asking is because ModelContainer is the one that does all the sync magically. Or is this too much of an overhead and users can open the app to keep the widget updated?
Replies
0
Boosts
0
Views
704
Activity
Jul ’26
Sandboxed App <> Launch Agent - how to communicate?
I’m building a sandboxed macOS App Store app that registers an agent using SMAppService. I’m trying to understand the IPC setup between the main app and the SMAppService-managed agent. The obvious options seem to be: XPC with a Mach service But from what I understand, I’d need a special entitlement that allows me to communicate over XPC Mach service - which is unlikely to pass Mac App Store review. So how do people communicate with processes registered with SMAppService?
Replies
2
Boosts
0
Views
1.2k
Activity
Jun ’26
Unable to enable login helper
I have one report from a customer, who migrated all data from his old MacBook to a new one. His is on Tahoe 26.5.1 (25F80). Here is my relevant code: + (BOOL)enableLoginItem:(BOOL)enable { NSOperatingSystemVersion osv = NSProcessInfo.processInfo.operatingSystemVersion; if (osv.majorVersion >= 13) { NSError* error; SMAppService* service = [SMAppService loginItemServiceWithIdentifier:MY_HELPER_APP_ID]; if (![service registerAndReturnError:&error] && error) @throw error; return YES; } return SMLoginItemSetEnabled((__bridge CFStringRef)MY_HELPER_APP_ID, enable); } What should I do to re-enable the login helper?
Replies
2
Boosts
0
Views
1.2k
Activity
Jun ’26
Can SMAppService Daemon replace SMJobBless for exclusive HID capture from keyboards?
To gain exclusive access to keyboard HID devices like Amazon Fire Bluetooth remote controls, my app has been installing a privileged helper tool with SMJobBless in the past. The app - which also has Accessibility permissions - then invoked and communicated with that helper tool through XPC. Now I'm looking into replacing that with a daemon installed through the newer SMAppService APIs, but running into a permission problem: If I try to exclusively open a keyboard HID device from the SMAppService-registered XPC service/daemon (which runs as root as seen in Activity Monitor), IOHIDDeviceOpen returns kIOReturnNotPermitted. I've spent many hours now trying to get it to work, but so far didn't find a solution. Could it be that XPC services registered as a daemon through SMAppService do not inherit the TCC permissions from the invoking process (here: Accessibility permissions) - and the exclusive IOHIDDeviceOpen therefore fails?
Replies
9
Boosts
0
Views
1k
Activity
Jun ’26
SMAppService - helper is not started
My software installs a privileged daemon using the SMAppService api. After removing the executables and recompiling the software I sometimes find that it needs to be registered again. After doing this, i.e. ensuring the application is properly registered and enabled in Login Items & Extensions the helper is not run when initiated from XPC. SMAppService.status has returned .enabled, and there is a valid job dictionary for the helper. I check the job dictionary with a function called updatePenaltyBoxStatus() that was given to me by a friend but I think originated from Apple. If I logoff (or reboot), login again, manually open Login Items & Extensions to check registration, then retry the application, it works. I don't mind doing this but it is probably a bit much for a lot of my users. Is there a reliable way to do this programatically? Here is my Swift translation of updatePenaltyBoxStatus. I fetch the job dictionary with SMJobCopyDictionary() prior to calling isInPenaltyBox(). I also had to write C wrapper functions for the WIFEXITED and WIFEXITSTATUS macros. func isInPenaltyBox(_ dict: Dictionary<String, Any>?) -> Bool { guard let jobDict = dict else { // If the helper was in the penalty box, unregistering it doesn't change that. So don't override a previous helperInPenaltyBox value return m_penalty_box } if let lastExitStatusObj = jobDict["LastExitStatus"] as? NSNumber { let lastExitStatus = lastExitStatusObj.intValue if wifexited(Int32(lastExitStatus)) == 0 { // It might've stopped or exited due to a signal or whatever. // Regardless, it didn't meet our criteria for winding up in the penalty box. m_penalty_box = false } // Now get the exit status and check for `EX_CONFIG`. let status = wexitstatus(Int32(lastExitStatus)) let newInPenaltyBox = status == EX_CONFIG if m_penalty_box != newInPenaltyBox { Logger.instance.log( "Penalty box change: " + m_ident + " old: " + String(m_penalty_box) + " new: " + String(newInPenaltyBox)) } m_penalty_box = newInPenaltyBox } return m_penalty_box }
Replies
2
Boosts
0
Views
1.1k
Activity
May ’26
SMAppService.daemon and AirWatch installation
My enterprise app requires a launch daemon that provides services to support my Security agent plugin. I bundle everything in an App and install using AirWatch. This all used to work until something changed, either AirWatch or the MacOS version. Now the install fails because my SMAppService instance returns an error when .register is called: Error Domain=SMAppServiceErrorDomain Code=1 "Operation not permitted" UserInfo={NSLocalizedFailureReason=Operation not permitted} If I install by opening my installer package as a user, the install always succeeds. The app is an enterprise app and is not distributed through the App Store. The app also installs a security extension. The security extension is installed and activated before any calls to SMAppService. I can't figure out what has changed in the last few months that would cause the error, or how to fix this. Any help or pointers would be appreciated.
Replies
6
Boosts
0
Views
590
Activity
Apr ’26
How to modify the launchctl config to start Postfix?
On Sequoia, I want to configure my postfix as a server. And for this I have to change the way postfix is started from: /System/Library/LaunchDaemons/com.apple.postfix.master.plist But this file is on the read only / file system. Then I just unloaded this startup, and made a new one in: /Library/LaunchDaemons/com.apple.postfix.master.plist and I was able to start it. But on the next system boot, the system one in /System/Library/LaunchDaemons was started again. How should I cleanly and permanently achieve this server basic modification?
Replies
3
Boosts
0
Views
528
Activity
Mar ’26
Securing XPC Daemon Communication from Authorization Plugin
I'm working on securing communication between an Authorization Plugin and an XPC daemon, and I’d appreciate some guidance on best practices and troubleshooting. The current design which, I’ve implemented a custom Authorization Plugin for step-up authentication, which is loaded by Authorization Services at the loginwindow (inside SecurityAgent). This plugin acts as an XPC client and connects to a custom XPC daemon. Setup Details 1. XPC Daemon Runs as root (LaunchDaemon) Not sandboxed (my understanding is that root daemons typically don’t run sandboxed—please correct me if this is wrong) Mach service: com.roboInc.AuthXpcDaemon Bundle identifier: com.roboInc.OfflineAuthXpcDaemon 2. Authorization Plugin Bundle identifier: com.roboInc.AuthPlugin Loaded by SecurityAgent during login 3. Code Signing Both plugin and daemon are signed using a development certificate What I’m Trying to Achieve I want to secure the XPC communication so that: The daemon only accepts connections from trusted clients The plugin only connects to the legitimate daemon Communication is protected against unauthorized access The Issue I'm facing I attempted to validate code signatures using: SecRequirementCreateWithString SecCodeCopyGuestWithAttributes SecCodeCheckValidity However, validation consistently fails with: -67050 (errSecCSReqFailed) Could you please help here What is the recommended way to securely authenticate an Authorization Plugin (running inside SecurityAgent) to a privileged XPC daemon? Since the plugin runs inside SecurityAgent, how can the daemon reliably distinguish my plugin from other plugins? What is the correct approach to building a SecRequirement in this scenario? Any guidance, examples, or pointers would be greatly appreciated. Thanks in advance!
Replies
6
Boosts
0
Views
1.6k
Activity
Mar ’26
libswiftCompatibilitySpan.dylib missing in XCode 26.3
A macOS privileged helper tool that uses SubProcess crashes on intel Macs (running macOS 13 - 15: unable to test on macOS 26 on intel) with the error that libswiftCompatibilitySpan.dylib cannot be loaded when built with XCode 26.3. The same helper tool works as expected with XCode 26.2. The helper is installed using SMAppService. When I remove the dependency for SubProcess, the crash no longer occurs (but important functionality is also disabled).
Replies
9
Boosts
0
Views
764
Activity
Mar ’26
LaunchAgent (Mac) as peripheral doesn't show a pairing request.
The same code built in a regular Mac app (with UI) does get paired. The characteristic properties are [.read, .write, .notify, .notifyEncryptionRequired] The characteristic permissions are [.readEncryptionRequired, .writeEncryptionRequired] My service is primary. In the iOS app (central) I try to read the characteristic, but an error is reported: Error code: 5, Description: Authentication is insufficient.
Replies
9
Boosts
0
Views
1.9k
Activity
Mar ’26
Migrating away from SMJobBless
I have migrated my code to use SMAppService but am running into trouble deleting the old SMJobBless launchd registration using launchd remove. I am invoking this from a root shell when I detect the daemon and associated plist still exist, then also deleting those files. The remove seems to work (i.e. no errors returned) but launchd list shows the service is registered, with a status code of 28 I am using the same label for SMAppService as previously and suspect this is the reason for the problem. However, I am reluctant to change the label as there will a lot of code changes to do this. If I quit my application, disable the background job in System Settings and run sudo launchd remove in the Terminal then it is removed and my application runs as expected once the background job is re-enabled. Alternatively, a reboot seems to get things going. Any suggestions on to how I could do this more effectively welcome.
Replies
2
Boosts
0
Views
930
Activity
Mar ’26