I am trying to create a client connection to a SystemExtension IOService. I can see that my IOUserClient
subclass is created (init()
and Start(IOService*)
is called), but the return code from IOServiceOpen
returns kIOReturnNotPermitted
.
I am making the call to IOServiceOpen
from the same app that creates the activation request.
Entitlements for app that makes the activation request / call to IOServiceOpen
:
<?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.userclient-access</key>
<array>
<string>sc.example.MyUserUSBInterfaceDriver</string>
</array>
<key>com.apple.developer.system-extension.install</key>
<true/>
<key>com.apple.developer.system-extension.uninstall</key>
<true/>
</dict>
</plist>
Entitlements for the dext:
<?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.userclient-access</key>
<array>
<string>sc.example.USBApp</string>
</array>
<key>com.apple.developer.driverkit</key>
<true/>
<key>com.apple.developer.driverkit.transport.usb</key>
<true/>
</dict>
</plist>
MyUserClient:
#ifndef MyUserClient_h
#define MyUserClient_h
#include <DriverKit/IOUserClient.iig>
class MyUserClient : public IOUserClient {
public:
bool init() override;
kern_return_t Start(IOService* provider) override;
kern_return_t Stop(IOService* provider) override;
void free() override;
};
#endif /* MyUserClient_h */
bool MyUserClient::init() {
LOG();
if (!super::init()) {
LOG("super::init() failed");
return false;
}
return true;
}
kern_return_t IMPL(MyUserClient, Start) {
LOG();
auto ret = Start(provider, SUPERDISPATCH);
if (ret != kIOReturnSuccess) {
LOG("SUPERDISPATCH Start failed, ret: %{public}d", ret);
}
return ret;
}
kern_return_t IMPL(MyUserClient, Stop) {
LOG();
auto ret = Stop(provider, SUPERDISPATCH);
if (ret != kIOReturnSuccess) {
LOG("SUPERDISPATCH Stop failed, ret: %{public}d", ret);
}
return ret;
}
void MyUserClient::free() {
super::free();
LOG();
}
LOG
is just a macro that does os_log(OS_LOG_DEFAULT, ...
NewUserClient
implementation:
kern_return_t IMPL(MyUserUSBInterfaceDriver, NewUserClient) {
LOG("%{public}d:", type);
IOService* client;
auto ret = Create(this, "UserClientProperties", &client);
*userClient = OSDynamicCast(IOUserClient, client);
if (!(*userClient) || ret != kIOReturnSuccess) {
LOG("Failed to create IOUserClient, %{public}d", ret);
}
return ret;
}
Code to connect to system extension:
void connectToDext(io_service_t* serviceObject) {
io_connect_t dataPort;
kern_return_t kernResult =IOServiceOpen(*serviceObject, mach_task_self(), 123, &dataPort);
if (kernResult != KERN_SUCCESS) {
printf("IOServicceOpen failed: %d, %s\n", kernResult, kern_return_t_toCStr(kernResult));
}
kernResult = IOServiceClose(dataPort);
if (kernResult != KERN_SUCCESS) {
printf("IOServicceClosed failed: %d, %s\n", kernResult, kern_return_t_toCStr(kernResult));
}
}
int connectToFirstDext() {
CFMutableDictionaryRef matchingDict;
matchingDict = IOServiceMatching("IOService");
if (matchingDict == 0) {
return -1;
}
io_iterator_t iter;
if (IOServiceGetMatchingServices(kIOMasterPortDefault, matchingDict, &iter) !=
KERN_SUCCESS) {
printf("IOServiceGetMatchingServices failed.\n");
return -1;
}
io_service_t device;
while ((device = IOIteratorNext(iter))) {
io_name_t deviceName;
if (IORegistryEntryGetName(device, deviceName) == KERN_SUCCESS) {
printf("name: %s\n", deviceName);
if (strcmp(deviceName, "MyUserUSBInterfaceDriver") == 0) {
printf("Calling connect\n");
connectToDext(&device);
}
}
IOObjectRelease(device);
}
IOObjectRelease(iter);
return 0;
}
Edit:
Info.plist of 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>BuildMachineOSBuild</key>
<string>19E287</string>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>USBApp</string>
<key>CFBundleIdentifier</key>
<string>sc.example.USBApp</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>USBApp</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSupportedPlatforms</key>
<array>
<string>MacOSX</string>
</array>
<key>CFBundleVersion</key>
<string>1</string>
<key>DTCompiler</key>
<string>com.apple.compilers.llvm.clang.1_0</string>
<key>DTPlatformBuild</key>
<string>11E503a</string>
<key>DTPlatformVersion</key>
<string>GM</string>
<key>DTSDKBuild</key>
<string>19E258</string>
<key>DTSDKName</key>
<string>macosx10.15</string>
<key>DTXcode</key>
<string>1141</string>
<key>DTXcodeBuild</key>
<string>11E503a</string>
<key>LSMinimumSystemVersion</key>
<string>10.15</string>
<key>NSHumanReadableCopyright</key>
<string>Copyright © 2020 Example. All rights reserved.</string>
<key>NSMainNibFile</key>
<string>MainMenu</string>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
<key>NSSupportsAutomaticTermination</key>
<true/>
<key>NSSupportsSuddenTermination</key>
<true/>
</dict>
</plist>
Info.plist of dext:
<?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>BuildMachineOSBuild</key>
<string>19E287</string>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>sc.example.MyUserUSBInterfaceDriver</string>
<key>CFBundleIdentifier</key>
<string>sc.example.MyUserUSBInterfaceDriver</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>sc.example.MyUserUSBInterfaceDriver</string>
<key>CFBundlePackageType</key>
<string>DEXT</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSupportedPlatforms</key>
<array>
<string>MacOSX</string>
</array>
<key>CFBundleVersion</key>
<string>1</string>
<key>DTCompiler</key>
<string>com.apple.compilers.llvm.clang.1_0</string>
<key>DTPlatformBuild</key>
<string>11E503a</string>
<key>DTPlatformVersion</key>
<string>GM</string>
<key>DTSDKBuild</key>
<string></string>
<key>DTSDKName</key>
<string>driverkit.macosx19.0</string>
<key>DTXcode</key>
<string>1141</string>
<key>DTXcodeBuild</key>
<string>11E503a</string>
<key>IOKitPersonalities</key>
<dict>
<key>example_device</key>
<dict>
<key>CFBundleIdentifier</key>
<string>sc.example.MyUserUSBInterfaceDriver</string>
<key>IOClass</key>
<string>IOUserService</string>
<key>IOProviderClass</key>
<string>IOUSBHostInterface</string>
<key>IOUserClass</key>
<string>MyUserUSBInterfaceDriver</string>
<key>IOUserServerName</key>
<string>sc.example.MyUserUSBInterfaceDriver</string>
<key>UserClientProperties</key>
<dict>
<key>IOClass</key>
<string>IOUserUserClient</string>
<key>IOServiceDEXTEntitlements</key>
<string></string>
<key>IOUserClass</key>
<string>MyUserClient</string>
</dict>
<key>bConfigurationValue</key>
<integer>1</integer>
<key>bInterfaceNumber</key>
<integer>0</integer>
<key>idProduct</key>
<integer>8</integer>
<key>idVendor</key>
<integer>1234</integer>
</dict>
</dict>
<key>OSBundleUsageDescription</key>
<string>Example user space USB driver</string>
<key>OSMinimumDriverKitVersion</key>
<string>19.4</string>
</dict>
</plist>
The IOServiceDEXTEntitlements
property in your IOKitPersonality's Info.plist
's user client property dictionary should be one of:
A non-array or empty-array IOServiceDEXTEntitlements
property means the client can't match the entitlements in one of the inner arrays, as there aren't any. The check therefore always fails with kIOReturnNotPermitted
. This is what's happening with your (empty) string value.
For details, check the code in IOUserServer::checkEntitlements()
and where it's called from in IOUserServer::serviceNewUserClient()
in IOUserServer.cpp from the xnu source code.
(Given prior to the contents of the Info.plist
s being posted.)
I don't see anything obviously wrong with what you've posted, so I suspect your problem might be caused by something you haven't posted. Things to watch out for:
com.apple.developer.driverkit.userclient-access
array must contain the dext's bundle ID. Perhaps double-check that this ID really is equal to sc.example.MyUserUSBInterfaceDriver
? (I've previously spent over an hour tearing my hair out over the kIOReturnNotPermitted
error when I had a typo here.)IOServiceDEXTEntitlements
key, the user space app must have all entitlements listed there. (This dictionary comes from the dext's info.plist, which you haven't posted yet at time of writing.)TeamIdentifier
using codesign -dv path/to/your.dext
and codesign -dv path/to/your.app