How to empirically determine what actually blocks usbipd-mac on macOS, and how to turn that into evidence Apple can act on.
FB22897007 ("Ship a first-party USB/IP server for macOS") described the blocker as:
it requires the
com.apple.security.device.usbentitlement to rebind host USB drivers. That entitlement request was submitted in August 2025 and denied on 25 February 2026.
Apple replied:
com.apple.security.device.usbentitlement does not require entitlement request to use. You should be able to add it to your app's entitlements file directly without going through a formal approval process.
Apple's answer is correct, and it answers a different question than the one we meant to ask. The report named the wrong entitlement. Apple responded accurately about that entitlement, we did not correct the record within two weeks, and the report was closed on 4 Aug 2026 and is no longer monitored.
com.apple.security.device.usb is an App Sandbox entitlement. It appears in Apple's
documentation under App Sandbox → Hardware, and its only function is to punch a hole
in the sandbox for a process that has com.apple.security.app-sandbox enabled. Two
consequences follow:
usbipdis a non-sandboxed daemon. An entitlement that relaxes a sandbox has nothing to relax in a process that is not sandboxed. Adding it tousbipd.entitlements— which the project already does — is expected to be a no-op.- Nothing about the App Sandbox governs IOKit driver matching. Whether a USB device is already bound to an in-kernel driver, and whether userspace may take it away, is decided entirely outside the sandbox.
Detaching a USB device from its in-kernel driver requires a DriverKit driver matching the device at a higher probe score, which requires this family of managed entitlements:
| Entitlement | Approval |
|---|---|
com.apple.developer.driverkit |
Apple review required |
com.apple.developer.driverkit.transport.usb |
Apple review required |
com.apple.developer.driverkit.allow-any-userclient-access |
Apple review required |
These are managed capabilities: they are only honoured when the same keys appear in an Apple-issued provisioning profile embedded in the signed binary. Ad-hoc signing them does not work — AMFI kills the process at launch. That launch failure is itself reproducible evidence, and the validation harness captures it.
This is the request that was denied on 25 February 2026. It is a materially higher bar than the App Sandbox entitlement Apple pointed at, and it is the thing worth re-filing about.
Sources/SystemExtension/SystemExtension.entitlements is the file that actually ships —
.github/workflows/release.yml signs the system extension bundle with it. Four of its
eight keys were wrong, and all four have now been corrected:
| Key | Problem |
|---|---|
com.apple.developer.driverkit.usb.transport |
Transposition of ...driverkit.transport.usb. Not a real key, so it was silently ignored and could never match a provisioning profile. |
com.apple.developer.system-extension.request |
Not a real key. ...system-extension.install is the only one, and it belongs on the binary that calls OSSystemExtensionRequest. |
com.apple.security.iokit-user-client-class |
Not a real key. The real form is com.apple.security.temporary-exception.iokit-user-client-class, an App Sandbox exception with no effect on a non-sandboxed extension. |
com.apple.developer.endpoint-security.client |
Real, but unrelated to USB and separately reviewed. Bundling it broadened the pending request well past what this project needs. |
This matters beyond tidiness. If the entitlement request filed in August 2025 was built from this key list, it asked Apple for a USB transport entitlement that does not exist, plus Endpoint Security. Check what the pending request actually says in the Developer portal before re-filing.
usbipd.entitlements was separately dead — nothing referenced it — and carried
com.apple.security.get-task-allow, a debug entitlement that lets any process attach a
debugger and that fails notarization. It is now the entitlements file for the usbipd
binary, carrying com.apple.developer.system-extension.install, which that binary needs
because it is the one submitting the extension for installation.
Scripts/validate-usb-entitlements.sh audits both files on every run and will catch a
regression. It parses the plists rather than grepping them, so the comments recording
what was removed do not read as the keys still being present.
A managed capability is only honoured when the same keys appear in an Apple-issued
provisioning profile embedded in the bundle as Contents/embedded.provisionprofile.
codesign will embed DriverKit entitlement keys into a signature without complaint and
without that profile, producing a build that looks correctly signed and silently fails to
claim devices at runtime.
The release workflow now embeds a profile from the DRIVERKIT_PROVISIONING_PROFILE
secret (base64-encoded .provisionprofile), warns loudly when that secret is absent, and
reads the entitlements back out of the finished signatures rather than trusting what was
passed in. The secret cannot be populated until Apple approves the request.
Scripts/validate-usb-entitlements.sh compiles one standalone probe
(Scripts/entitlement-validation/USBClaimProbe.swift), signs it five times with
different entitlement sets, and runs each build against the USB devices currently
attached. Comparing the runs isolates the effect of each entitlement.
| Variant | Entitlements | What it measures |
|---|---|---|
baseline |
none | What usbipd-mac can do today |
usb-only |
device.usb |
Apple's suggestion, taken literally |
sandboxed-only |
app-sandbox |
Negative control for the pair below |
sandboxed-usb |
app-sandbox + device.usb |
The only context where device.usb is defined to do anything |
driverkit |
DriverKit family | Expected to be denied at launch — the real gate |
For each attached device the probe records:
- which kernel driver classes are currently attached below the device in the IORegistry;
- the result of
IOCreatePlugInInterfaceForServiceandUSBDeviceOpen; - per interface, the attached driver and the result of
USBInterfaceOpen; - optionally (
--seize) the result ofUSBDeviceOpenSeize/USBInterfaceOpenSeize.
The interface-level result is the one that matters. A USB/IP server has to own the interfaces to forward transfers, and interfaces are the level at which in-kernel drivers bind.
# Attach the device you actually want to share first — a serial adapter, a debug
# probe, a board in DFU mode. Then:
./Scripts/validate-usb-entitlements.sh
# Non-destructive survey only: who owns what, no opens attempted
./Scripts/validate-usb-entitlements.sh --list-only
# Root changes some IOKit outcomes — capture both
sudo ./Scripts/validate-usb-entitlements.sh
# Try to take a device away from its current driver. This can disconnect it.
./Scripts/validate-usb-entitlements.sh --seizeOutputs land in .build/entitlement-validation/:
<variant>.json— machine-readable results per variant<variant>.log— console output per variant<variant>.effective-entitlements.xml— what the signature actually carries, read back from the binary rather than assumedreport.md— cross-variant comparison, ready to attach to a Feedback report
If baseline, usb-only, and sandboxed-usb are identical — the expected outcome —
that is a direct, reproducible demonstration that com.apple.security.device.usb does
not grant usbipd-mac anything, and the report's premise (that this key was the blocker)
was wrong in a way that does not help.
Per-device, the Kernel driver column splits the fleet in two:
- No driver listed — the device is already fully usable from userspace, today, with no entitlement of any kind. Typically vendor-specific-class devices: many debug probes, DFU/bootloader modes, and boards that expose a raw vendor interface.
- A driver listed (
AppleUSBACM,IOUSBHostHIDDevice,IOUSBMassStorageDriverNub,AppleUSBFTDI,AppleUSBAudio, …) — the device is claimed by the kernel and cannot be served without DriverKit-level rebinding.
That split is worth knowing on its own. The README currently states the project "will not work until approved"; if a meaningful share of embedded hardware falls into the first category, a device-class-scoped release is possible without waiting on Apple at all.
If --seize succeeds where a plain open failed, that is a third path worth
investigating: USBInterfaceOpenSeize can displace some clients without DriverKit.
Independently of entitlements, Sources/SystemExtension/IOKit/DeviceClaimer.swift
attempts to claim devices by setting IOMatchCategory and IOProbeScore registry
properties from userspace and calling IOServiceRequestProbe. Setting registry
properties on a live IOService from userspace routes to the driver's setProperties(),
which the USB host drivers do not implement for these keys — so this path does not
unbind anything, and would not do so even with the DriverKit entitlements granted.
The probe deliberately measures the real capability (can the interface be opened) rather than exercising that code path, so the results are not confounded by it. Fixing the claim strategy is separate work, and only worth doing once the measurements say which of the three paths above is viable.
The DriverKit request — "DriverKit UserClient Access, DriverKit USB Transport - VendorID, DriverKit" — was denied. The reply redirected it:
Please request the
com.apple.developer.usb.host-controller-interfaceinstead of DriverKit (reviewIOUSBHostControllerInterface).
That entitlement does not solve this project's problem.
IOUSBHostControllerInterface is for implementing a USB host controller — presenting
devices to macOS. That is what a USB/IP client needs, so that a Mac can consume a
device shared by another machine. usbipd-mac is a server: it takes devices macOS
has already enumerated and offers them to other machines. Nothing about a virtual host
controller detaches an AppleUserHIDDevice from a keyboard.
So Apple has declined the capability this server would need and offered one aimed at the opposite direction of traffic. Reading the reply generously, the reviewer saw "USB/IP on macOS" and answered the more common request.
Two things follow.
For this server, the blocked device classes stay blocked. Nothing in the reply
changes what validate-usb-entitlements.sh measures, and re-submitting the same
DriverKit request unchanged is unlikely to land differently.
A macOS USB/IP client is a real possibility, and is a different product. The
entitlement Apple named is managed, but the request volume is low enough that it was
never added to the developer portal — requests go through Feedback Assistant in the
format the denial email specifies. It can also be skipped entirely during development:
IOUSBHostControllerInterface works for a process running as root on a system with SIP
disabled. carlossless/usbip-macos is an
existing experimental client that takes exactly that route.
Nothing here blocks shipping. The driver-free CLI release needs no entitlement at all —
see driver-free-release.md. The steps below matter only if the blocked device classes
(USB-serial, HID, mass storage) are being pursued.
-
Run the harness with the target hardware attached, as both user and root.
-
The portal state is known. For App ID
com.usbipd.mac.system-extension(team 592A3U6J26), the Capability Requests tab reads:Capability Status DriverKit USB Transport - VendorID Declined DriverKit UserClient Access Declined DriverKit PCI (development) Assigned — confirmed, see the caveat below DriverKit USB Transport - VendorID and ProductID No Requests DriverKit Family Serial Submitted 2026-08-06, request ID 26F53XCAGY DriverKit Family HID Device No Requests DriverKit Transport HID No Requests Two things follow. The account is not blanket-blocked from DriverKit — a PCI capability is assigned — so the declines are about these specific asks. And the declined request was the broad one: USB Transport scoped to a vendor ID grants access to every device from that vendor. The narrower VendorID and ProductID variant has never been requested, nor have the per-family capabilities.
The Serial request is the one outstanding. It asks for that family alone, at the development tier, and deliberately omits UserClient Access — declined in February, and unnecessary because the dext and the daemon are signed by the same team. See
driverkit-serial-request.mdfor the submitted text.That matters for what is worth asking for next. A narrowly scoped request is a much smaller ask than a vendor-wide one, and
DriverKit Family Serialis the capability that maps to the USB-serial adapters this project most often gets asked about. Both are untried.The catch is that per-device scoping suits a targeted tool, not a general-purpose USB/IP server: approval would cover only the vendor and product IDs named in it.
There is a development tier, and it is the cheaper question to answer. The Capabilities tab lists the DriverKit entries — including
DriverKit Family Serial (development)andDriverKit USB Transport (development)— annotated "Development only" and "Provisioning support required". These are not self-serve:DriverKit PCI (development)shows as Assigned under Capability Requests, so the development variants go through the same request flow.The PCI row is confirmed
Assigned, but is weak precedent. A legible view of the Capability Requests tab confirms it. What it does not establish is why: the account holder does not recall requesting it, and on the Capabilities tab the same row sits unchecked without the "Provisioning support required" annotation every other DriverKit row carries. The likeliest reading is that some development-tier capabilities are assigned to Developer Program accounts without an explicit request.So the account does hold it, and saying so is accurate. Do not extend that into "this team has been granted a DriverKit request on merit" — an earlier revision of this document did, and that inference is not supported. Either it was misread, or some development capabilities are assigned to Developer Program accounts without a request. Under the second reading the account does hold it, but it is not evidence that Apple granted this team a development DriverKit request — which is the weight it was originally given here. Verify the row directly before citing it.
A development capability plus a DriverKit development provisioning profile would answer the question this project has never been able to test: whether a DriverKit extension can actually take a USB device from its in-kernel driver. Every measurement so far establishes only that userspace cannot. Development builds are not distributable, so this proves the mechanism rather than shipping it — but a working demonstration is a far stronger production request than a description.
Note also that the App ID currently has only System Extension enabled (
com.apple.developer.system-extension.install), which is the subsystem this project quarantined. DriverKit needs a dext, a different bundle type, shipped inside an app in/Applications. An approval would arrive against infrastructure that does not exist yet. -
Once approved: create the provisioning profile, base64-encode it, and set it as the
DRIVERKIT_PROVISIONING_PROFILErepository secret. -
Update the README warning to name the correct entitlement and, if the results support it, to scope the warning to device classes that are actually blocked.
Filing a new Feedback report was previously listed here. It is not a prerequisite for any of the above and has been dropped.