USBDriverKit trying to change IOProviderClass and create a IOUSBHostDevice subclass

I have a project that runs correctly when this is set in the dext Info.plist:

IOClass: IOUserService
IOProviderClass: IOUserResources
IOUserClass: MyCustomDriver
IOUserServerName: $(PRODUCT_BUNDLE_IDENTIFIER)

I'm trying to adjust this so that I can do Driverkit development with USB. I've gotten my development entitlements correct (driverkit.transport.usb) and my dext is [activated, ready].

I've tried changing the IOProviderClass to IOUSBHostDevice. I've tried IOClass set to IOService as well as IOUserService. I've also added idProduct and idVendor keys to both Info.plist and the Driverkit Entitlements file.

My dext is properly set up in the system with these changes, but Console.app lists that it has loaded it as a codeless dext. I need my dext implementation to execute. Does anyone have any suggestions?

Thanks.

When matching a USB device, make sure to review this article: https://developer.apple.com/news/?id=zk5xdwbn

Also, please ensure that if you matching a device based on its vendor ID, you must have an entitlement granted for that vendor ID, and your entitlement should contain only the idVendor key, so that it matches the value in your provisioning profile. For example:

<key>com.apple.developer.driverkit.transport.usb</key>
<array>
  <dict>
    <key>idVendor</key>
    <integer>1234</integer>
  </dict>
</array>

I have SIP disabled and system extension developer mode turned on. I do not have an entitlement granted from Apple. Is this required even to do development?

I’m attempting to write a driver for an open source hardware platform. I was intending to seek an entitlement from Apple once I verified a proof of concept was possible through DriverKit.

Is it executing as a codeless dext because it isn’t matching properly with my test device?

I have been consulting the linked article, but it wasn’t very clear how to set up my Info.plist to match against a non-HID composite USB device.

Is there any way to match with a non-HID device for development purposes? I have requested an entitlement but would just like to continue development on my local machine. My USB transport dext passes the entitlement check (it seems) but executes as a "codeless dext". I have gotten the USBHIDKeyboard example to work on my hardware, but it does seem USB transport access is more strict.

If an entitlement is required even for local development, this is the information I find misleading:

https://developer.apple.com/system-extensions/

"While your request is in review, you can test system extensions on your Mac by temporarily turning off System Integrity Protection."

https://developer.apple.com/documentation/driverkit/debugging_and_testing_system_extensions

"When you activate a system extension from your app, the system requires your extension to have the proper entitlements and code signature. It must also meet all other criteria for running on the user’s system. If the extension doesn’t meet all of the requirements, the activation request fails with an error. During the development of a system extension, you can disable some validation checks to simplify writing and testing your code."

My dext has the DriverKit USB Transport entitlement with SIP disabled and system extensions developer mode on. It passes the entitlement verification and systemextensionsctl lists it as "activated, enabled". The above piece of documentation states that the activation request would fail with an error, but the activation request is succeeding.

It doesn't seem clear which part of this process is not working properly. The documentation you linked works fine for the USBHIDKeyboard dext, but the same keys do not work for USB transport or with a IOUSBHostDevice provider. If this is an issue with not having an entitlement, the documentation stating the activation request would fail with an error seems misleading.

(Replying in the main thread as I reached the character limit.)

Info.plist for Driver:

<?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>IOKitPersonalities</key>
	<dict>
		<key>HackRFDriver</key>
		<dict>
			<key>CFBundleIdentifier</key>
			<string>info.maddie.HackRFProto.HackRFDriver</string>
			<key>IOClass</key>
			<string>IOUserService</string>
			<key>IOProviderClass</key>
			<string>IOUSBHostDevice</string>
			<key>IOResourceMatch</key>
			<string>IOKit</string>
			<key>IOUserClass</key>
			<string>HackRFDriver</string>
			<key>IOUserServerName</key>
			<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
			<key>ProductID</key>
			<integer>10296</integer>
			<key>VendorID</key>
			<integer>3034</integer>
		</dict>
	</dict>
	<key>OSBundleUsageDescription</key>
	<string></string>
</dict>
</plist>

Entitlements:

<?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>3034</integer>
		</dict>
	</array>
</dict>
</plist>

Output of ioreg -b -n "RTL2838UHIDIR" -r -l :

+-o [1mRTL2838UHIDIR[0m@02310000  <class IOUSBHostDevice, id 0x100004dcd, registered, matched, active, busy 0 (19 ms), retain 20>
  | {
  |   "sessionID" = 526303539846
  |   "USBSpeed" = 3
  |   "idProduct" = 10296
  |   "iManufacturer" = 1
  |   "bDeviceClass" = 0
  |   "IOPowerManagement" = {"PowerOverrideOn"=Yes,"DevicePowerState"=2,"CurrentPowerState"=2,"CapabilityFlags"=32768,"MaxPowerState"=2,"DriverPowerState"=0}
  |   "bcdDevice" = 256
  |   "bMaxPacketSize0" = 64
  |   "iProduct" = 2
  |   "iSerialNumber" = 3
  |   "bNumConfigurations" = 1
  |   "USB Product Name" = "RTL2838UHIDIR"
  |   "USB Address" = 9
  |   "locationID" = 36765696
  |   "bDeviceSubClass" = 0
  |   "bcdUSB" = 512
  |   "kUSBSerialNumberString" = "00000001"
  |   "kUSBCurrentConfiguration" = 1
  |   "IOCFPlugInTypes" = {"9dc7b780-9ec0-11d4-a54f-000a27052861"="IOUSBHostFamily.kext/Contents/PlugIns/IOUSBLib.bundle"}
  |   "bDeviceProtocol" = 0
  |   "USBPortType" = 0
  |   "IOServiceDEXTEntitlements" = (("com.apple.developer.driverkit.transport.usb"))
  |   "USB Vendor Name" = "Realtek"
  |   "Device Speed" = 2
  |   "idVendor" = 3034
  |   "kUSBProductString" = "RTL2838UHIDIR"
  |   "USB Serial Number" = "00000001"
  |   "IOGeneralInterest" = "IOCommand is not serializable"
  |   "kUSBAddress" = 9
  |   "kUSBVendorString" = "Realtek"
  | }
  | 
  +-o [1mAppleUSBHostCompositeDevice[0m  <class AppleUSBHostCompositeDevice, id 0x100004dd2, !registered, !matched, active, busy 0, retain 4>
  |   {
  |     "IOClass" = "AppleUSBHostCompositeDevice"
  |     "CFBundleIdentifier" = "com.apple.driver.usb.AppleUSBHostCompositeDevice"
  |     "IOProviderClass" = "IOUSBHostDevice"
  |     "kUSBPreferredConfiguration" = 1
  |     "IOProbeScore" = 50000
  |     "IOMatchedAtBoot" = Yes
  |     "IOMatchCategory" = "IODefaultMatchCategory"
  |     "bDeviceSubClass" = 0
  |     "IOPersonalityPublisher" = "com.apple.driver.usb.AppleUSBHostCompositeDevice"
  |     "CFBundleIdentifierKernel" = "com.apple.driver.usb.AppleUSBHostCompositeDevice"
  |     "IOPrimaryDriverTerminateOptions" = Yes
  |     "bDeviceClass" = 0
  |   }
  |   
  +-o [1mBulk-In, Interface[0m@0  <class IOUSBHostInterface, id 0x100004dd3, registered, matched, active, busy 0 (9 ms), retain 5>
  |   {
  |     "USBSpeed" = 3
  |     "iInterface" = 5
  |     "bInterfaceProtocol" = 255
  |     "bAlternateSetting" = 0
  |     "idProduct" = 10296
  |     "bcdDevice" = 256
  |     "USB Product Name" = "RTL2838UHIDIR"
  |     "locationID" = 36765696
  |     "bInterfaceClass" = 255
  |     "bInterfaceSubClass" = 255
  |     "IOCFPlugInTypes" = {"2d9786c6-9ef3-11d4-ad51-000a27052861"="IOUSBHostFamily.kext/Contents/PlugIns/IOUSBLib.bundle"}
  |     "USBPortType" = 0
  |     "kUSBString" = "Bulk-In, Interface"
  |     "bInterfaceNumber" = 0
  |     "bConfigurationValue" = 1
  |     "USB Vendor Name" = "Realtek"
  |     "idVendor" = 3034
  |     "IOServiceDEXTEntitlements" = (("com.apple.developer.driverkit.transport.usb"))
  |     "bNumEndpoints" = 1
  |     "USB Serial Number" = "00000001"
  |   }
  |   
  +-o [1mBulk-In, Interface[0m@1  <class IOUSBHostInterface, id 0x100004dd4, registered, matched, active, busy 0 (7 ms), retain 5>
      {
        "USBSpeed" = 3
        "iInterface" = 5
        "bInterfaceProtocol" = 255
        "bAlternateSetting" = 0
        "idProduct" = 10296
        "bcdDevice" = 256
        "USB Product Name" = "RTL2838UHIDIR"
        "locationID" = 36765696
        "bInterfaceClass" = 255
        "bInterfaceSubClass" = 255
        "IOCFPlugInTypes" = {"2d9786c6-9ef3-11d4-ad51-000a27052861"="IOUSBHostFamily.kext/Contents/PlugIns/IOUSBLib.bundle"}
        "USBPortType" = 0
        "kUSBString" = "Bulk-In, Interface"
        "bInterfaceNumber" = 1
        "bConfigurationValue" = 1
        "USB Vendor Name" = "Realtek"
        "idVendor" = 3034
        "IOServiceDEXTEntitlements" = (("com.apple.developer.driverkit.transport.usb"))
        "bNumEndpoints" = 0
        "USB Serial Number" = "00000001"
      }

On this page, I found this documentation:

https://developer.apple.com/documentation/kernel/implementing_drivers_system_extensions_and_kexts

"Create a codeless dext when the system provides DriverKit support for your hardware. A codeless dext isn’t entirely codeless. It contains a minimal executable file with an empty subclass—that is, a subclass of an existing DriverKit class, where you don’t implement any methods. In the Info.plist file of your dext, set the value of the IOUserClass key to the name of your custom subclass. At runtime, the system instantiates your class, but all method calls fall through to the implementation of the parent class."

In Console.app, one of the outputs is:

kernelmanagerd : Loading codeless extension: Dext info.maddie.HackRFProto.HackRFDriver v1 in executable dext bundle info.maddie.HackRFProto.HackRFDriver at /Library/SystemExtensions/80995607-A587-4769-B65B-BF0DBAA42CF7/info.maddie.HackRFProto.HackRFDriver.dext

I'm not sure if I should be subclassing from something other than IOService, or why my dext is running codeless, but I can't figure out how to get it to actually execute and bind to the device. I don't want to subclass IOUSBHostDevice, as I want that to be the provider class. I may be going at this the wrong way completely, but I would like the provider passed in to be an IOUSBHostDevice, so that I can open the interfaces myself and communicate with the device.

The reason your dext is being identified as "codeless" is due to your plist settings. You're using ProductID and VendorID, but those are the keys used for HID matching. As shown in the table on https://developer.apple.com/library/archive/qa/qa1076/_index.html as well as the ioreg output, the correct keys to use are idProduct and idVendor. For USB matching, your matching keys should always match the format of the values in the I/O Registry. Give that a shot and report back.

USBDriverKit trying to change IOProviderClass and create a IOUSBHostDevice subclass
 
 
Q