Migrating a codeless KEXT to a codeless DEXT
Asked Answered
S

1

5

I am migrating a codeless KEXT to a codeless DEXT. I have watched the WWDC video and read much of the information on the Apple Developer site. The difficulty I am having is finding not what to do but how to get started. A nice tutorial with an example project would help.

In my codeless KEXT, for 4 separate devices I have IOKitPersonalities for IOUSBDevice and IOUSBInterface for each device. The KEXT allowed me to match my devices to my "driver" so the Apple HID driver wouldn't grab them. I wish to do the same or something similar in the codeless DEXT.

So far, I have created a DriverKit target (for a DriverKit.framework) called MyUsbDriver in an app and added a USBDriverKit.framework. That added a folder MyUsbDriver to my project with files MyUsbDriver.cpp, MyUsbDriver.iig, Info.plist and MyUsbDriver.entitlements. Here are my questions:

  1. It looks like the default subclass of IOService is OK for USB - that is the same as the IOClass from the KEXT. Is that true?

  2. Is IOUSBHostInterface in DEXT-world equivalent to IOUSBInterface in KEXT-world?

  3. Is IOUSBHostDevice equivalent to IOUSBDevice?

  4. Do I need to do anything to the .cpp or .iig for codeless DEXT? Isn't most of my work to be done in the plist and entitlements files?

  5. Do I need the USBDriverKit.framework in my Frameworks and Libraries of MyUsbDriver target?

  6. Where can I find a decent example of how to complete this migration?

Any help would be greatly appreciated.

Update:

Using the example and other links in the answer I was able to get something together. I did have a "Doh" moment: My initial test project type was Command Line Tool and I could never get the DEXT to embed. I almost just hand-edited the pbxproj file. However, in looking at the original example USBApp from Scott Knight, I realized the project type he was using was App, In hindsight, that makes sense but at the time was confounding.

Here is the info.plist I have so far to match on one of our deprecated devices:

<?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>IOKitPersonalities</key>
    <dict>
        <key>MyUsbDrver</key>
        <dict>
            <key>CFBundleIdentifier</key>
            <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
            <key>CFBundleIdentifierKernel</key>
            <string>com.apple.kpi.iokit</string>
            <key>IOClass</key>
            <string>IOUserService</string>
            <key>IOMatchCategory</key>
            <string>com.apple.null.driver</string>
            <key>IOProviderClass</key>
            <string>IOUsbHostInterface</string>
            <key>IOResourceMatch</key>
            <string>IOKit</string>
            <key>IOUserClass</key>
            <string>MyUsbDrver</string>
            <key>IOUserServerName</key>
            <string>Home.MyUsbDrver</string>
            <key>bConfigurationValue</key>
            <integer>1</integer>
            <key>bInterfaceNumber</key>
            <integer>0</integer>
            <key>idProduct</key>
            <integer>2</integer>
            <key>idVendor</key>
            <integer>5843</integer>
        </dict>
    </dict>
    <key>OSBundleUsageDescription</key>
    <string>Codless DEXT to match on IOKit.</string>
</dict>
</plist>

I am not sure about IOResourceMatch - the value is IOKit, which is the direction I am trying to go.

Update the Second:

Progress!

I ended up having to manually change the signing provisions in my pbxproj file. Disabled SIP, set up System Extension activation/deactivation in my app and did command-line signing. I found this repository to be helpful with a decent Objective-C example for the activation code - https://github.com/google/santa.git. Everything builds and code signing seemed to be successful. Getting the fun error

SystemExtension "Home.MyUsbDrver" request did fail: Error Domain=OSSystemExtensionErrorDomain Code=8 "(null)"

Update 3:

I checked my DEXT and app entitlements, and it looked like the app entitlements needed to be updated. This is what I have now for 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.security.app-sandbox</key>
    <true/>
    <key>com.apple.security.files.user-selected.read-only</key>
    <true/>
    <key>com.apple.developer.system-extension.install</key>
    <true/>
    <key>com.apple.developer.system-extension.uninstall</key>
    <true/>
</dict>
</plist>

I was missing the bottom two. Cleaned my project, built, signed again. When I tried running from Xcode, still got the error. When I ran my app from Finder, I got the system preferences dialog. After that, still the same result from Xcode, and now nothing but a flash of the app when run from Finder. I rebooted - still the same results. However, from terminal when I run systemextensionsctl -list, I get:

3 extension(s)
--- com.apple.system_extension.driver_extension
enabled active  teamID  bundleID (version)  name    [state]
        <REDACTED>  Home.MyUsbDrver (1.0/1) Home.MyUsbDrver [terminated waiting to uninstall on reboot]
*   *   <REDACTED>  Home.MyUsbDrver (1.0/1) Home.MyUsbDrver [activated enabled]
        <REDACTED>  Home.MyUsbDrver (1.0/1) Home.MyUsbDrver [activated waiting to upgrade]

After a reboot I get this:

1 extension(s)
--- com.apple.system_extension.driver_extension
enabled active  teamID  bundleID (version)  name    [state]
*   *   <REDACTED>  Home.MyUsbDrver (1.0/1) Home.MyUsbDrver [activated enabled]

So, it looks like my system extension is in place, but I am actually not sure why since I just did a fresh reboot and have not run my app.

Update 4:

I figured out the problem with my entitlements was just the format of the file. I changed it in TextEdit and I can now communicate with my device. Here is what I ended up with:

<?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.transport.usb</key>
    <array>
        <dict>
            <key>idVendor</key>
            <integer>VID0</integer>
            <key>idProductArray</key>
            <array>
                <integer>PID0</integer>
                <integer>PID1</integer>
                <integer>PID2</integer>
                <integer>PID3</integer>
                <integer>PID4</integer>
            </array>
        </dict>
    </array>
    <key>com.apple.security.app-sandbox</key>
    <true/>
</dict>
</plist>
Sarita answered 2/8, 2020 at 6:5 Comment(0)
A
3

I was banging my head hard against getting the same thing to work. In the end I managed to get a working DEXT that disables the Apple HID driver for specific vendor ID/product ID combinations. We have obtained the DriverKit entitlement for our vendor ID.

  1. It looks like the default subclass of IOService is OK for USB - that is the same as the IOClass from the KEXT. Is that true?

This worked for me. I tried removing the .iig and .cpp files completely, but unlike KEXTs, it seems that there needs to be some code compiled in order for signing to work properly. So I ended up with just an empty subclass of IOService.

  1. Is IOUSBHostInterface in DEXT-world equivalent to IOUSBInterface in KEXT-world?

I believe so. I used IOUSBHostInterface and we had IOUSBInterface in our KEXT.

  1. Is IOUSBHostDevice equivalent to IOUSBDevice?

I don't know, but I believe so.

  1. Do I need to do anything to the .cpp or .iig for codeless DEXT? Isn't most of my work to be done in the plist and entitlements files?

I did not need to change anything in the .cpp and .iig files. You might want to delete the os_log(OS_LOG_DEFAULT, "Hello World"); line in the .cpp file before you release it. But while debugging, it was useful for me to tell whether the DEXT was actually loading or not. You can run log stream --source | grep 'HELLO' in a terminal to look for the log.

  1. Do I need the USBDriverKit.framework in my Frameworks and Libraries of MyUsbDriver target?

My DEXT links against DriverKit.framework. I don't know if it's needed or not.

  1. Where can I find a decent example of how to complete this migration?

Maybe these can help:

Some notes I jotted down for myself and future developers

During development of a DriverKit extension (dext), do the following:

  • Disable system integrity protection (SIP): https://apple.stackexchange.com/a/208481/21491. (Reboot in recovery mode, run csrutil disable). Remember to enable it again!

  • Enable system extension development mode by running systemextensionsctl developer on

  • Make sure you don't have your old codeless KEXT installed. (Delete it from /Library/Extensions and/or /System/Library/Extensions. Make sure to reboot afterwards)

Tips and cautions

  • You might need a manual provisioning profile that contains the DriverKit entitlements. I think my problem was that I got the DriverKit entitlement on an enterprise developer team instead of a team for public development.

  • The app that loads the extension needs the "System Extension" entitlement, but does not need a manual provisining profile.

  • Be ware of a stupid bug in System Preferences. You need to consent to loading the dext every time it gets loaded. However, if the "Security & Privacy" pane is already open, it will not show the button to give the consent. You need to restart System Preferences for it to show up. I've been using the command pkill -9 "System Preferences"; open /System/Library/PreferencePanes/Security.prefPane from Terminal generously to workaround this.

  • You can use systemextensionsctl to uninstall the dext or reset the system state. However, this does not actually change the driver matching, so you need to reboot. Generously. I used this Terminal command because I'm lazy: osascript -e 'tell app "System Events" to restart'.

  • You can use ioreg to check whether devices are being matched to the extension or not: ioreg -lirc IOUSBHostInterface.

  • The key to getting the extension to work is to set the IOProviderClass to IOUSBHostInterface instead of IOResources in the Info.plist file. (For reference, the KEXT uses IOUSBInterface which is one of the classes that Apple has deprecated)

  • You might want to bump the version in Info.plist every time you make changes to your DEXT to make sure that you are actually using the correct one. (systemextensionsctl will show the version it has loaded).

Abolition answered 4/8, 2020 at 13:52 Comment(7)
Thanks for the information - 2 days later and I've already looked at the references you linked, and those are the links that have helped me the most. I'm to the point now of mucking with the entitlements and SIP so I can test. Or at least try to!Sarita
I added the info.plist I have so far for the DEXT. If you see any glaring issues, I would appreciate a heads-up.Sarita
I compared your plist to mine. I didn't see any significant differences.Abolition
Thanks both for working through this issue in the open. I've now been able to build a "codeless" DEXT that disables the Apple Mass Storage driver for a device that I can now communicate with over WebUSB. Basically I started off with github.com/stuartlynne/USBApp-updated and changed the .cpp and .iig files to match the XCode DriverKit template. Now to try and obtain a DriverKit entitlement from Apple.Slush
See my third update - I am a little stumped now. I think it's working but not working?Sarita
@GTAE86, I'm not sure what your question in the third update is? But when an app requests the system to load a DEXT, the DEXT will be loaded on every reboot. This lasts until the app is deleted or the app requests uninstallation. Does this help you?Abolition
@JonasDueVesterheden Yes - I was not clear on the lifetime. That sounds good. Now I just have to debug the crashing part. Thanks for all your help!Sarita

© 2022 - 2024 — McMap. All rights reserved.