Search code examples
c++xcodeiokitdriverkit

Connection between client and DriverKit in Xcode


In a Xcode project (macOS app), I'm using the DriverKit(and HIDDriverKit) framework. I have encountered a problem in the connection between the client app and the driver, which is implemented by the "IOKit" framework. By calling the function "IOServiceGetMatchingServices" the value of "iterator" returns correctly and then communication with the driver is done. However, after releasing the version on the TestFlight, on some systems, the value of the "iterator" returned 0 and it is not possible to communicate with the driver. I checked the status of the activated driver with the command "systemextensionsctl list" and there are no problems on the driver side and the values of "Enabled" and "Active" are starred.

AppSandbox = True, SIP: enable

ret = IOServiceGetMatchingServices(kIOMainPortDefault, IOServiceNameMatching(dextIdentifier), &iterator);
if (ret != kIOReturnSuccess)
{
    goto fail;
}

while ((service = IOIteratorNext(iterator)) != IO_OBJECT_NULL) {
    ret = IOServiceOpen(service, mach_task_self(), 0, &connection);
    if(ret == kIOReturnSuccess)
    {
        break;
    }
    else 
    {
        syslog(LOG_WARNING, "Error");
    }
    IOObjectRelease(service);
}

The returned value of the "ret" is 0 (kIOReturnSuccess) always, But the "iterator" is null (0).

Solved: By adding the com.apple.security.temporary-exception.iokit-user-client-class entitlement it's solved. thanks to @pmdj


Solution

  • A null iterator is (unfortunately?) a valid output from IOServiceGetMatchingServices when there are no matching services. There's no guarantee it'll be null when there are no matches, but you have to accept it as possible output.

    For example, the following tiny program triggers a null iterator on my system:

    #include <IOKit/IOKitLib.h>
    #include <stdio.h>
    
    int main()
    {
        io_iterator_t iterator = IO_OBJECT_NULL;
        IOReturn ret = IOServiceGetMatchingServices(MACH_PORT_NULL,
            IOServiceNameMatching("MadeUpNameThatDefinitelyDoesntExist"), &iterator);
        printf("IOServiceGetMatchingServices -> 0x%x, iterator = 0x%x\n", ret, iterator);
        if (iterator != IO_OBJECT_NULL)
            IOObjectRelease(iterator);
    }
    

    When run:

    $ ./matching-services-null-iterator 
    IOServiceGetMatchingServices -> 0x0, iterator = 0x0
    

    You would expect no matching services when your driver hasn't matched any devices, for example. So you should be able to reproduce the issue by running the code with no device plugged in.

    Update:

    It seems that the app is sandboxed, in which case you need to specify any user client classes you expect to be using in the app's entitlements. This can be done using the com.apple.security.temporary-exception.iokit-user-client-class entitlement, which for a DriverKit extension should be "IOUserUserClient", the kernel I/O Kit class that acts as the back-end for any dext userclient subclass.