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!

Answered by DTS Engineer in 903561022
what exactly are these requirements?

That question makes no sense because com.apple.developer.service-management.managed-by-main-app isn’t a real entitlement, in the sense defined by Determining if an entitlement is real.

The [com.apple.developer. prefix] hints that this would only be needed during development

No, that’s not how to read this. Rather, the com.apple.developer. prefix means that:

  • This entitlement is available to be used by third-party developers [1].
  • But it’s restricted, that is, it must be authorised by a provisioning profile (the unrestricted entitlements have a com.apple.security. prefix). TN3125 Inside Code Signing: Provisioning Profiles talks about these concepts in more detail.

[1] To be clear, not all entitlements available to third-party developers have this prefix. Some entitlements were created before this convention was established.

should the same plist also be embedded by the helper tool binary via -sectcreate __TEXT __launchd_plist?

No. The system creates the launchd job using the property list file as a template. The __TEXT / __launchd_plist is an SMJobBless thing. It’s not relevant to SMAppService.

Now, it might make sense to embed an Info.plist section, but more on that below.

Is it true that XPC_CONNECTION_MACH_SERVICE_PRIVILEGED should be omitted … ?

No. If you’re talking to a privileged helper, you should always set the privileged flag. XPC Resources has a link to a post where I explain this.

If one needs … to perform some actions with root privileges, what exactly would enabling the App Sandbox … accomplish?

It could potentially allow you to deploy on the Mac App Store (-:

The App Sandbox is compatible with programs running as root, with the restrictions imposed by the sandbox still applying. This is an obscure combination, but it does work and there are circumstances where you need it. For example, a Network Extension provider that’s packaged as a system extension runs as root, but NE requires that you enable the App Sandbox.

In theory such a provider should be deployable via the Mac App Store, but I don’t know if a lot of folks actually use that in practice.

When it comes to SMAppService, if the container app is sandboxed then (starting in macOS 14.2) the daemon must also be sandboxed.

In theory such a daemon would be compatible with the Mac App Store. Honestly, I’ve no idea what App Review would make of that.

If your daemon is sandboxed then it will need an Info.plist because the bundle ID in that tells the system how to set up its app container. You can give it an Info.plist either by putting it in the __TEXT / __info_plist section or by embedded the daemon in an app-like wrapper. See Signing a daemon with a restricted entitlement for advice on how to do the latter.

Generally I prefer that second option, not least because it then lets your daemon use restricted entitlements.

LLMs give a ton of contradicting advice on this topic.

Now if only your LLMs were trained to respond with “Search the forums and do what Quinn said!” (-:

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

As it happens, shortly after posting I had a hunch that the com.apple.developer.service-management.managed-by-main-app entitlement may not be needed at all.

That entitlement features on the GitHub repo LLMs are likely training on: https://github.com/malpern/privileged_helper_help/tree/main

The .developer suffix hints that this would only be needed during development, but my best guess is that the fact that my main app uses a provisioning profile in both Debug and Release configuration somehow plays a role. Either way, removing that entitlement from the Helper tool suddenly allowed the connection to be started automatically.

It would be great to know the answers to the other questions, since trial-and-error sometimes leads to half-truths:

  • 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? Would this requirement, if it exists, be true for all versions of macOS where SMAppService is now available (13 > 27)?
  • Is it true that XPC_CONNECTION_MACH_SERVICE_PRIVILEGED should be omitted when creating the client connection, if the helper tool is managed via SMAppService API? My current working version has it, but if the LLM’s claim of its obsolescence is true, is this something that might break in previous/future versions of macOS, for example?
  • 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?

I don't know much about root issues with apps. But this question seems like it might be useful: https://developer.apple.com/forums/thread/792826

I think that the term "privileged helper" historically referred to an older way for apps to temporarily gain root privileges. Apple didn't like that and pushed people towards launch daemons. Lots more information here: https://developer.apple.com/forums/thread/708765

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?

Again, I'm not sure about anything involving root. But I have discovered certain benefits to sandboxing everything. If you have any part that requires (or typically uses) sandboxing, then all parts should be sandboxed. It greatly helps with interoperability between different apps or different components within apps.

If you need to break out of the sandbox, you can do that with an unsandboxed XPCService. But you can only do this with a true XPCService. For other types of XPC communication, then you can't cross the sandbox line.

Don't use the comments feature. They hide your replies.

For better or worse the App Sandbox is not a good option for our software.

That's not what I'm saying. App Sandbox opts you into a lot of modern behaviour and expectations. It's literally the default.

But all you need to do is add an unsandboxed XPC service. The whole OS, and random, unsuspecting APIs, run via XPC. You can't avoid it.

the moment your app starts using the newer APIs, a few behaviors are clearly different.

Certainly. But the old behaviours are deprecated. They may break at any time, especially if root is involved.

The nice part is that launch daemons are the intended application for much of these technologies. The official documentation assumes a launch daemon. But if you're trying to do a launch agent, then you have to cobble together information from various places and try to make it work. I did finally get it to work, but it took me a year. But you could just run through the standard examples and see if that exhibits the same behaviour.

@Etresoft I appreciate the response but this is getting off topic fast. I hope someone from DTS can answer the remaining questions.

Both those old threads, the existing information online, and the LLMs that seem to be trained on both, don't actually provide the information I am looking for.

Accepted Answer
what exactly are these requirements?

That question makes no sense because com.apple.developer.service-management.managed-by-main-app isn’t a real entitlement, in the sense defined by Determining if an entitlement is real.

The [com.apple.developer. prefix] hints that this would only be needed during development

No, that’s not how to read this. Rather, the com.apple.developer. prefix means that:

  • This entitlement is available to be used by third-party developers [1].
  • But it’s restricted, that is, it must be authorised by a provisioning profile (the unrestricted entitlements have a com.apple.security. prefix). TN3125 Inside Code Signing: Provisioning Profiles talks about these concepts in more detail.

[1] To be clear, not all entitlements available to third-party developers have this prefix. Some entitlements were created before this convention was established.

should the same plist also be embedded by the helper tool binary via -sectcreate __TEXT __launchd_plist?

No. The system creates the launchd job using the property list file as a template. The __TEXT / __launchd_plist is an SMJobBless thing. It’s not relevant to SMAppService.

Now, it might make sense to embed an Info.plist section, but more on that below.

Is it true that XPC_CONNECTION_MACH_SERVICE_PRIVILEGED should be omitted … ?

No. If you’re talking to a privileged helper, you should always set the privileged flag. XPC Resources has a link to a post where I explain this.

If one needs … to perform some actions with root privileges, what exactly would enabling the App Sandbox … accomplish?

It could potentially allow you to deploy on the Mac App Store (-:

The App Sandbox is compatible with programs running as root, with the restrictions imposed by the sandbox still applying. This is an obscure combination, but it does work and there are circumstances where you need it. For example, a Network Extension provider that’s packaged as a system extension runs as root, but NE requires that you enable the App Sandbox.

In theory such a provider should be deployable via the Mac App Store, but I don’t know if a lot of folks actually use that in practice.

When it comes to SMAppService, if the container app is sandboxed then (starting in macOS 14.2) the daemon must also be sandboxed.

In theory such a daemon would be compatible with the Mac App Store. Honestly, I’ve no idea what App Review would make of that.

If your daemon is sandboxed then it will need an Info.plist because the bundle ID in that tells the system how to set up its app container. You can give it an Info.plist either by putting it in the __TEXT / __info_plist section or by embedded the daemon in an app-like wrapper. See Signing a daemon with a restricted entitlement for advice on how to do the latter.

Generally I prefer that second option, not least because it then lets your daemon use restricted entitlements.

LLMs give a ton of contradicting advice on this topic.

Now if only your LLMs were trained to respond with “Search the forums and do what Quinn said!” (-:

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Thank you @DTS Engineer for the answers and the overall course correction. I'm fully to blame for not even considering the entitlement had been hallucinated, silly me seeing it on that GitHub repo made me think this was coming from an actual human.

PrivilegedHelperTool no longer launches automatically after SMJobBless to SMAppService
 
 
Q