3

I am working on migrating a codeless KEXT to DriverKit. It is used to disable the IOKit HID driver for USB devices that present themselves as HID compliant in firmware upgrade mode.

So far I have managed to match an empty subclass of IOService to the relevant devices. Here's an example of the IOKitPersonalities entries I'm using:

<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>IOProviderClass</key>
    <string>IOUSBHostInterface</string>
    <key>IOResourceMatch</key>
    <string>IOKit</string>
    <key>IOUserClass</key>
    <string>DriverKitTestExtension</string>
    <key>IOUserServerName</key>
    <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
    <key>bConfigurationValue</key>
    <integer>1</integer>
    <key>bInterfaceNumber</key>
    <integer>0</integer>
    <key>idVendor</key>
    <integer><!-- USB Vendor ID --></integer>
    <key>idProduct</key>
    <integer><!-- USB Product ID --></integer>
</dict>

Is it correct to use IOUSBHostInterface as the provider class for this use case? I've also tried using the old (deprecated) IOUSBInterface, but it has the same problems as IOUSBHostInterface.

The new DEXT is working but I am seeing some bad performance regressions in our firmware update code. Calls to libusb are taking tens of seconds. If I use the old KEXT, they return immediately.

Here are some example traces of the problem:

   5 redacted 3168.0  libusb_claim_interface ..../libusb/Sources/libusb/core.c:1310
   4 redacted 3168.0  darwin_claim_interface ..../libusb/Sources/libusb/darwin_usb.c:1089
   3 IOUSBLib 1668.0  IOUSBInterfaceClass::USBInterfaceOpen(bool)
   2 IOKit 1668.0  io_service_wait_quiet
   1 libsystem_kernel.dylib 1668.0  mach_msg
   0 libsystem_kernel.dylib 1668.0  mach_msg_trap

And:

   7 redacted 1859.0  libusb_get_device_list ..../libusb/Sources/libusb/core.c:632
   6 redacted 1859.0  darwin_get_device_list ..../libusb/Sources/libusb/darwin_usb.c:780
   5 redacted 1859.0  process_new_device ..../libusb/Sources/libusb/darwin_usb.c:726
   4 redacted 1766.0  darwin_check_configuration ..../libusb/Sources/libusb/darwin_usb.c:540
   3 IOKit 1766.0  IOIteratorNext
   2 IOKit 1766.0  io_iterator_next
   1 libsystem_kernel.dylib 1766.0  mach_msg
   0 libsystem_kernel.dylib 1766.0  mach_msg_trap
   0 libsystem_kernel.dylib 1766.0  mach_msg_trap

These are recorded in the "Time Profiler" instrument with "Record Waiting Threads" enabled.

Can I do anything in the DEXT to fix this problem? I've tried subclassing IOUSBHostInterface instead of IOService, but that made no difference.

Here's the relevant output from running "ioreg -lirc IOUSBHostInterface":

+-o IOUSBHostInterface@0  
  | {
  |   "USBSpeed" = 1
  |   "iInterface" = 0
  |   "IOServiceLegacyMatchingRegistryID" = 4294971983
  |   "bInterfaceProtocol" = 0
  |   "bAlternateSetting" = 0
  |   "idProduct" = 
  |   "bcdDevice" = 292
  |   "USB Product Name" = 
  |   "locationID" = 338690048
  |   "bInterfaceClass" = 3
  |   "bInterfaceSubClass" = 0
  |   "IOCFPlugInTypes" = {"2d9786c6-9ef3-11d4-ad51-000a27052861"="IOUSBHostFamily.kext/Contents/PlugIns/IOUSBLib.bundle"}
  |   "USBPortType" = 0
  |   "bConfigurationValue" = 1
  |   "bInterfaceNumber" = 0
  |   "USB Vendor Name" = 
  |   "IOServiceDEXTEntitlements" = (("com.apple.developer.driverkit.transport.usb"))
  |   "idVendor" = 
  |   "bNumEndpoints" = 2
  |   "IOGeneralInterest" = "IOCommand is not serializable"
  |   "IOClassNameOverride" = "IOUSBInterface"
  | }
  | 
  +-o DriverKitTestExtension  
      {
        "IOClass" = "IOUserService"
        "CFBundleIdentifier" = 
        "IOProviderClass" = "IOUSBHostInterface"
        "IOUserServerCDHash" = "faa70138281d36b53946591685ccdceba4a5d638"
        "idProduct" = 
        "IOResourceMatch" = "IOKit"
        "bConfigurationValue" = 1
        "IOProbeScore" = 90000
        "IOMatchCategory" = "com.apple.null.driver"
        "IOUserServerName" = 
        "IOMatchedPersonality" = {"IOClass"="IOUserService","CFBundleIdentifier"=" ","IOProviderClass"="IOUSBHostInterface","IOUserServerCDHash"="faa70138281d36b53946591685ccdceba4a5d638","idProduct"=,"IOResourceMatch"="IOKit","bConfigurationValue"=1,"IOMatchCategory"="com.apple.null.driver","IOUserServerName"=,"idVendor"=,"CFBundleIdentifierKernel"="com.apple.kpi.iokit","bInterfaceNumber"=0,"IOUserClass"="DriverKitTestExtension"}
        "idVendor" = 
        "CFBundleIdentifierKernel" = "com.apple.kpi.iokit"
        "bInterfaceNumber" = 0
        "IOUserClass" = "DriverKitTestExtension"
      }

Any input is welcome!

  • Out of curiosity, I tried changing the old codeless KEXT to use `IOUSBHostInterface` (like the DEXT) instead of `IOUSBInterface` for `IOProviderClass`. Performance was still fine. – Jonas Due Vesterheden May 14 '20 at 09:47

1 Answers1

2

I finally found the problem! After reading How to set `com.apple.developer.driverkit.transport.usb` entitlement?, I decided to experiment with the entitlements for my DEXT. This made me realize that the DEXT was not being loaded at all.

I changed the DEXT entitlements from:

<!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>
    <true/>
</dict>
</plist>

To:

<!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><!-- USB Vendor ID --></integer>
        </dict>
    </array>
</dict>
</plist>

After this, the log message from my IOService subclass is now showing up (using log stream with grep). Performance during the firmware upgrade is back to normal.

  • I'm looking into writing a codeless dext to prevent a specific device from mounting using IOUSBMassStorageDriver, so that I can then access it via WebUSB. Were you successful in the end? Do you know if a codeless dext can be installed independently of an app? Any pointers on where to start? – Gerrit Jul 30 '20 at 15:47
  • @Gerrit Yes, I was able to prevent the standard IOKit HID drivers from matching specific USB vendor ID/product ID. I think you should post a new SO question instead of discussing here in the comments. If you link to your question from here, I'll see if I can answer. – Jonas Due Vesterheden Aug 03 '20 at 06:56
  • As a side note, I don't know much about WebUSB, but I would be surprised if you would be allowed to access mass storage from a browser. This question might be relevant: https://stackoverflow.com/questions/49162692/can-webusb-transfer-files-to-a-usb-mass-storage-device-or-act-like-dd – Jonas Due Vesterheden Aug 03 '20 at 06:57
  • Thanks, that gives me hope! :) I want to prevent the IOKit MassStorage drivers from matching a specific USB vendor ID & product ID, in which case I should then be able to access it from WebUSB. I'm using https://github.com/stuartlynne/USBApp-updated as a start until I can obtain a DriverKit entitlement. If I run into any specific issues, I'll be sure to post a new question. – Gerrit Aug 03 '20 at 10:11
  • I was going to post a new SO question, but it appears several exist already: - https://stackoverflow.com/questions/63212902/migrating-a-codeless-kext-to-a-codeless-dext - https://stackoverflow.com/questions/62442970/migrating-from-codeless-kext-to-dext-usb-interfaces-disappeared that would answer my question as well. – Gerrit Aug 03 '20 at 12:36