Hi everyone & DTS engineers,
I am developing a macOS application that uses Apple's Virtualization framework and vmnet APIs.
In my main application bundle, I have requested and received approval for the restricted entitlement com.apple.vm.networking. The main app works as expected with bridging/vmnet features.
Now, I have embedded a command-line helper binary inside the app bundle (Contents/MacOS/). The helper is configured as follows:
- Set up with
com.apple.security.app-sandbox = true - Inherits App Sandbox rules (
com.apple.security.inherit = true) - Signed with
com.apple.vm.networking = truein its entitlements file.
However, when launching or invoking networking features from this helper binary, it fails to execute the expected vmnet functions / gets blocked at runtime.
My questions for DTS / Apple Engineers:
- Since
com.apple.vm.networkingis a restricted entitlement tied to a specific App ID / Provisioning Profile, does an embedded CLI helper tool with its own Bundle ID need to be explicitly registered and granted this entitlement separately in the Developer Portal? - If the helper uses
com.apple.security.inherit, does AMFI still strictly evaluate the helper's own provisioning profile signature againstcom.apple.vm.networkingindependently of the main app bundle? - What is the recommended architectural pattern for vmnet access when using helper tools—should network creation stay strictly in the main app process and communicate via XPC, or should the helper tool be granted its own matching profile and entitlement?
Thanks in advance for any insight!
So this is a potential minefield [1], but I think you can make it work. The trick is to put the tool in an app-like wrapper [2], with its own bundle ID, and hence its own App ID, and then enable the VM Networking capability on that App ID. The tool then claims the required entitlements, with com.apple.vm.networking being a restricted entitlement that’s authorised by the tool’s provisioning profile.
I tried this in my office today (on macOS 26.7.1) and it seems to work a treat. Consider this:
% codesign -d --entitlements - EntitlementInheritanceExplorer.app/Contents/MacOS/EntitlementInheritanceChild.app
…
[Dict]
[Key] com.apple.application-identifier
[Value]
[String] SKMME9E2Y8.com.example.apple-samplecode.Child
[Key] com.apple.developer.team-identifier
[Value]
[String] SKMME9E2Y8
[Key] com.apple.security.app-sandbox
[Value]
[Bool] true
[Key] com.apple.security.get-task-allow
[Value]
[Bool] true
[Key] com.apple.security.inherit
[Value]
[Bool] true
[Key] com.apple.vm.networking
[Value]
[Bool] true
% security cms -D -i EntitlementInheritanceExplorer.app/Contents/MacOS/EntitlementInheritanceChild.app/Contents/embedded.provisionprofile | plutil -p -
{
…
"Entitlements" => {
"com.apple.application-identifier" => "SKMME9E2Y8.com.example.apple-samplecode.Child"
"com.apple.developer.team-identifier" => "SKMME9E2Y8"
"com.apple.vm.networking" => true
"keychain-access-groups" => [
0 => "SKMME9E2Y8.*"
]
}
…
}
When I have the parent spawn the child, it logs confirmation that it ran with the right entitlements and with the entitlements-validated flag set (the full log entries are at the end of this reply).
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"
[1] Due to the combination of sandbox inheritance (see Resolving App Sandbox Inheritance Problems) and the entitlements-validated flag (see App Groups: macOS vs iOS: Working Towards Harmony).
[2] See Signing a daemon with a restricted entitlement.
…
process: EntitlementInheritanceChild
subsystem: com.example.apple-samplecode.EntitlementInheritanceExplorer
category: child
message: first light
…
process: EntitlementInheritanceChild
subsystem: com.example.apple-samplecode.EntitlementInheritanceExplorer
category: child
message: is validated: true
…
process: EntitlementInheritanceChild
subsystem: com.example.apple-samplecode.EntitlementInheritanceExplorer
category: child
message: entitlement: com.apple.application-identifier = SKMME9E2Y8.com.example.apple-samplecode.Child
…
process: EntitlementInheritanceChild
subsystem: com.example.apple-samplecode.EntitlementInheritanceExplorer
category: child
message: entitlement: com.apple.developer.team-identifier = SKMME9E2Y8
…
process: EntitlementInheritanceChild
subsystem: com.example.apple-samplecode.EntitlementInheritanceExplorer
category: child
message: entitlement: com.apple.security.app-sandbox = 1
…
process: EntitlementInheritanceChild
subsystem: com.example.apple-samplecode.EntitlementInheritanceExplorer
category: child
message: entitlement: com.apple.security.get-task-allow = 1
…
process: EntitlementInheritanceChild
subsystem: com.example.apple-samplecode.EntitlementInheritanceExplorer
category: child
message: entitlement: com.apple.security.inherit = 1
…
process: EntitlementInheritanceChild
subsystem: com.example.apple-samplecode.EntitlementInheritanceExplorer
category: child
message: entitlement: com.apple.vm.networking = 1