Hello @all
I'm develop a DriverKit driver extension and without entitlement checks by OS everything runs fine. But if the entitlements check is enabled in the NVRAM then I get an error due connecting my IOUserClient instance. Which entitlements are really and exactly required for my driver?
My driver contains:
- one IOUserClient instance
- and multiple IOUserSerial instances
The bundle identifier of the driver ist:
org.eof.tools.VSPDriver
The bundle identifier of the client app
org.eof.tools.VSPInstall
My entire source code is available on GitHub if any one want to dive deep in :)
kernel[0:5107] () [VSPDriver]: NewUserClient called.
kernel[0:5107] () [VSPDriver]: CreateUserClient: create VSP user client from Info.plist.
kernel[0:5107] () [VSPUserClient]: init called.
kernel[0:5107] () [VSPUserClient]: init finished.
kernel[0:5107] () [VSPDriver]: CreateUserClient: check VSPUserClient type.
kernel[0:5107] () [VSPDriver]: CreateUserClient: success.
kernel[0:5107] () [VSPDriver]: NewUserClient finished.
kernel[0:5107] () [VSPUserClient]: Start: called.
kernel[0:5107] () [VSPUserClient]: User client successfully started.
kernel[0:389f] DK: VSPUserClient-0x100001127:UC failed userclient-access check, needed bundle ID org.eof.tools.VSPDriver
kernel[0:389f] DK: VSPUserClient-0x100001127:UC entitlements check failed
kernel[0:5107] () [VSPUserClient]: Stop called.
kernel[0:5107] () [VSPUserClient]: User client successfully removed.
kernel[0:5107] () [VSPUserClient]: free called.
Here my drivers entitlement file:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.developer.driverkit</key>
<true/>
<key>com.apple.developer.driverkit.allow-third-party-userclients</key>
<true/>
<key>com.apple.developer.driverkit.family.serial</key>
<true/>
</dict>
</plist>
Here my drivers Info.plist file
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>NSHumanReadableCopyright</key>
<string>Copyright © 2025 by EoF Software Labs</string>
<key>OSBundleUsageDescription</key>
<string>Provide virtual serial port</string>
<key>com.apple.developer.driverkit</key>
<true/>
<key>com.apple.developer.driverkit.allow-any-userclient-access</key>
<true/>
<key>com.apple.developer.driverkit.communicates-with-drivers</key>
<true/>
<key>com.apple.developer.system-extension.redistributable</key>
<true/>
<key>OSBundleLibraries</key>
<dict>
<key>com.apple.iokit.IOSerialFamily</key>
<string>1.0</string>
</dict>
<key>IOKitPersonalities</key>
<dict>
<key>VSPDriver</key>
<dict>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleIdentifierKernel</key>
<string>com.apple.kpi.iokit</string>
<key>IOMatchCategory</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>IOProviderClass</key>
<string>IOUserResources</string>
<key>IOResourceMatch</key>
<string>IOKit</string>
<key>IOProbeScore</key>
<integer>0</integer>
<key>IOClass</key>
<string>IOUserService</string>
<key>IOUserClass</key>
<string>VSPDriver</string>
<key>IOUserServerName</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>UserClientProperties</key>
<dict>
<key>IOClass</key>
<string>IOUserUserClient</string>
<key>IOUserClass</key>
<string>VSPUserClient</string>
</dict>
<key>SerialPortProperties</key>
<dict>
<key>CFBundleIdentifierKernel</key>
<string>com.apple.driver.driverkit.serial</string>
<key>IOProviderClass</key>
<string>IOSerialStreamSync</string>
<key>IOClass</key>
<string>IOUserSerial</string>
<key>IOUserClass</key>
<string>VSPSerialPort</string>
<key>HiddenPort</key>
<false/>
<key>IOTTYBaseName</key>
<string>vsp</string>
<key>IOTTYSuffix</key>
<string>0</string>
</dict>
</dict>
</dict>
</dict>
</plist>
Here the entitlements of the client app
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.developer.driverkit</key>
<true/>
<key>com.apple.developer.driverkit.allow-third-party-userclients</key>
<true/>
<key>com.apple.developer.driverkit.communicates-with-drivers</key>
<true/>
<key>com.apple.developer.shared-with-you</key>
<true/>
<key>com.apple.developer.system-extension.install</key>
<true/>
<key>com.apple.security.application-groups</key>
<array>
<string>$(TeamIdentifierPrefix).org.eof.apps</string>
</array>
</dict>
</plist>
Here the Info.plist of the client app:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSMinimumSystemVersion</key>
<string>$(MACOSX_DEPLOYMENT_TARGET)</string>
<key>com.apple.developer.driverkit</key>
<true/>
<key>com.apple.developer.driverkit.install</key>
<true/>
<key>com.apple.developer.system-extension.install</key>
<true/>
<key>com.apple.developer.system-extension.uninstall</key>
<true/>
<key>com.apple.developer.driverkit.userclient-access</key>
<array>
<string>VSPDriver</string>
</array>
<key>com.apple.private.driverkit.driver-access</key>
<array>
<string>VSPDriver</string>
</array>
<key>com.apple.security.temporary-exception.iokit-user-client-class</key>
<array>
<string>IOUserUserClient</string>
</array>
</dict>
</plist>
I'm develop a DriverKit driver extension and without entitlement checks by OS everything runs fine. But if the entitlements check is enabled in the NVRAM then I get an error due connecting my IOUserClient instance. Which entitlements are really and exactly required for my driver?
So, there are two different sides to this question. Starting with the DEXT:
-
DEXT have TOTAL control over who connects to them. The entitlement's here control who is allowed to "ask" to connect but the DEXT itself can accept or reject whatever it wants. Everything below ONLY controls that initial connection process, as the DEXT can always say "nah" and reject any connection it wants.
-
By default, DEXTs are only allowed to connect to processes signed by the same team as the DEXT. No entitlement is required for this, so if "your" DEXT will only talk to "your" app, then no entitlement is required.
-
On macOS, this can be expanded by using "com.apple.developer.driverkit.allow-any-userclient-access", which allows "any" process to attempt to connect.
-
On iPadOS, this can be expanded by using "com.apple.developer.driverkit.allow-third-party-userclients"
Now, moving to the connecting process:
-
By default, process are not allowed to connect to DEXTs, so without an entitlement the connection process will fail. I believe the enforcement mechanism is through the sandbox, so unsandboxed process maybe able to connect without the entitlement, but that's an edge case I'm not going to try and address.
-
On macOS, the "com.apple.developer.driverkit.userclient-access" entitlement defines exactly which DEXT a process can connect to. The value of that entitlement is an array of strings, where each entry in the array is the bundle ID of the DEXT that process can connect to.
-
On iPadOS, the "com.apple.developer.driverkit.communicates-with-drivers" entitlement allows an app to connect to user clients. No specific DEXT is specified on iPadOS.
Applying that specifically to macOS:
-
Any app that want to talk to a specific DEXT needs to request "com.apple.developer.driverkit.userclient-access" with the bundle ID(s) of the DEXT they want to interact with.
-
DEXT need no additional entitlement unless they want to accept connections from apps outside of their team.
__
Kevin Elliott
DTS Engineer, CoreOS/Hardware