PCIDriverKit entitlements during development

I'm trying to help out one of our vendors by building a skeleton PCI dext which they can flesh out.

However, I can't seem to get the signing right.

I can't sign it at all using no team or my personal team. "Signing for <app> requires a development team", and "Personal development teams ... do not support the System Extension capability".

I can't sign the driver because "DriverKit Team Provisioning Profile: <driver bundle id> doesn't match the entitlements file's value for the com.apple.developer.driverkit.transport.pci entitlement.

I think this problem occurs because our company has already been assigned a transport.pci entitlement, but for our own PCI vendor ID. But I want to build and test software that works with our vendor's PCI device.

I tried generating a profile for the driver manually, it contained only our own company's PCI driver match:

IOPCIPrimaryMatch = "0x0000MMMM&0x0000FFFF";

where MMMM is our own PCI vendor ID.

Is there a better way to inspect the profile Xcode is using than the postage-stamped sized info popup which truncates the information? I would download the generated profile but it doesn't appear on the profile, but Xcode is accessing it from somewhere.

When I look at the available capabilities I can add to an app identifier on the Developer portal, I see com.apple.developer.driverkit.transport.usb, which is "development only". There's no "development only" capability for PCI. Does this mean it isn't possible to develop even a proof-of-concept PCI driver without being first granted the DriverKit PCI (Primary Match) entitlement?

When adding capabilities to a driver, the list of available capabilities shown in Xcode has one "DriverKit PCI (Primary Match) entry", but if I double click it, two such entries appear in the Signing and Capabilities tab for my driver target. On the Developer portal, when I look at my driver's Identifier, there are two Capabilities labelled DriverKit PCI (Primary Match). Why?

Answered by DTS Engineer in 852427022

When I look at the available capabilities I can add to an app identifier on the Developer portal, I see com.apple.developer.driverkit.transport.usb, which is "development only". There's no "development only" capability for PCI.

Yes, and please file a bug about this and post the bug number back here. I don't know WHY there isn't a development only entitlement (I wasn't involved with DriverKit at the time), but it's a decision I'd like to revisit.

And yes...

Does this mean it isn't possible to develop even a proof-of-concept PCI driver without being first granted the DriverKit PCI (Primary Match) entitlement?

...that's exactly what it means. You could do this by disabling SIP (and possibly AMFI), but you can't use the more "elegant" flow the development entitlements allow.

In addition:

When adding capabilities to a driver, the list of available capabilities shown in Xcode has one "DriverKit PCI (Primary Match) entry", but if I double-click it, two such entries appear in the Signing and Capabilities tab for my driver target. On the Developer portal, when I look at my driver's Identifier, there are two Capabilities labelled DriverKit PCI (Primary Match). Why?

Because, unfortunately, DriverKit has always been the most complex codesign configuration on our platform, and Xcode 15 and 16 entirely support it properly. The issue in Xcode 16 (it was worse in Xcode 15) is that it doesn't understand that the same entitlement key can be granted twice. If you look VERY closely at the data you're shown, you can see that the two entries are actually:

(note the extra " " in the names):
DriverKit PCI (PrimaryMatch) -> 0x00001CFA&amp;0x0000FFFF
DriverKit PCI(PrimaryMatch) -> 0x0000bdbd&amp;0x0000FFFF

The problem here is that Xcode's automatic signing will ALWAYS pick one of those, never the other. To use the other one, you have to switch to manual code signing as described here.

Is there a better way to inspect the profile Xcode is using than the postage-stamped-sized info popup which truncates the information?

Sure. To start with, you can (currently) find the files themselves in:

~/Library/Developer/Xcode/UserData/Provisioning Profiles

One recommendation I'd have here is to not treat the contents of that folder as "precious" or special. What automatic code signing actually does is generate provisioning profiles "on demand", so if you delete an automatic profile... Xcode will just generate it again at the next build. Manually generating profiles is more cumbersome, but the solution there is to preserve them as a separate resource, probably as part of your project data, NOT to just "lose" them in the folder here. If they get deleted from Xcode's store, then you can just copy them back in from your own store (or using Xcode, which can manually download profiles as well).

The advantage of this approach is that when profiles "pile up" over time (which they tend to do), you can just delete* all of them then let Xcode regenerate the ones you're actually trying to investigate.

*Moving them somewhere else works too, but could indicate a fear of commitment.

In terms of looking at their contents, TN3125: Inside Code Signing: Provisioning Profiles has the details of how to see exactly what's there.

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

Accepted Answer

When I look at the available capabilities I can add to an app identifier on the Developer portal, I see com.apple.developer.driverkit.transport.usb, which is "development only". There's no "development only" capability for PCI.

Yes, and please file a bug about this and post the bug number back here. I don't know WHY there isn't a development only entitlement (I wasn't involved with DriverKit at the time), but it's a decision I'd like to revisit.

And yes...

Does this mean it isn't possible to develop even a proof-of-concept PCI driver without being first granted the DriverKit PCI (Primary Match) entitlement?

...that's exactly what it means. You could do this by disabling SIP (and possibly AMFI), but you can't use the more "elegant" flow the development entitlements allow.

In addition:

When adding capabilities to a driver, the list of available capabilities shown in Xcode has one "DriverKit PCI (Primary Match) entry", but if I double-click it, two such entries appear in the Signing and Capabilities tab for my driver target. On the Developer portal, when I look at my driver's Identifier, there are two Capabilities labelled DriverKit PCI (Primary Match). Why?

Because, unfortunately, DriverKit has always been the most complex codesign configuration on our platform, and Xcode 15 and 16 entirely support it properly. The issue in Xcode 16 (it was worse in Xcode 15) is that it doesn't understand that the same entitlement key can be granted twice. If you look VERY closely at the data you're shown, you can see that the two entries are actually:

(note the extra " " in the names):
DriverKit PCI (PrimaryMatch) -> 0x00001CFA&amp;0x0000FFFF
DriverKit PCI(PrimaryMatch) -> 0x0000bdbd&amp;0x0000FFFF

The problem here is that Xcode's automatic signing will ALWAYS pick one of those, never the other. To use the other one, you have to switch to manual code signing as described here.

Is there a better way to inspect the profile Xcode is using than the postage-stamped-sized info popup which truncates the information?

Sure. To start with, you can (currently) find the files themselves in:

~/Library/Developer/Xcode/UserData/Provisioning Profiles

One recommendation I'd have here is to not treat the contents of that folder as "precious" or special. What automatic code signing actually does is generate provisioning profiles "on demand", so if you delete an automatic profile... Xcode will just generate it again at the next build. Manually generating profiles is more cumbersome, but the solution there is to preserve them as a separate resource, probably as part of your project data, NOT to just "lose" them in the folder here. If they get deleted from Xcode's store, then you can just copy them back in from your own store (or using Xcode, which can manually download profiles as well).

The advantage of this approach is that when profiles "pile up" over time (which they tend to do), you can just delete* all of them then let Xcode regenerate the ones you're actually trying to investigate.

*Moving them somewhere else works too, but could indicate a fear of commitment.

In terms of looking at their contents, TN3125: Inside Code Signing: Provisioning Profiles has the details of how to see exactly what's there.

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

thank you Kevin for that answer.

In the meantime I've discovered a few more facts, which I'll detail here. I'll also file some bugs and attach their numbers here.

I did manage to get a PCI driver to match and install on a victim machine. I used an Xcode-generated profile that includes our own PCI entitlement, but installed the driver on a machine with entitlement checks turned off. To do this, on the victim machine:

  1. boot into recovery and turn SIP off (csrutil disable at the command line)
  2. boot back into the OS, and execute:
  sudo nvram boot-args="amfi_get_out_of_my_way=1 -arm64e_preview_abi  dk=0x8001"
  1. reboot to let the boot-args take effect
  2. change the architecture of the driver to arm64e (it was ${STANDARD_ARCHS} (in build settings/architectures)

It is possible that not all of the boot-args are necessary. I had to change the build architecture because it seems like the other arguments make the OS think that everything is a platform binary. The driver still failed entitlement checks until I added dk=0x8001.

All of this information takes a lot of searching to find (some of it comes from these very forums)

I then tried making a USB driver for development (for a vendor ID we don't have an entitlement for). On my usual Mac, the driver won't load because the entitlement in my provisioning profile is for a specific vendor ID - I can't choose the development USB transport capability. I would have to deploy this driver on a victim machine with SIP off and the same shenanigans as above. This probably wouldn't affect a team with no USB transport entitlement at all, they'd only be able to choose the development flavor of the capability.

In the meantime, I've discovered a few more facts, which I'll detail here. I'll also file some bugs and attach their numbers here.

Perfect, thank you.

I did manage to get a PCI driver to match and install on a victim machine. I used an Xcode-generated profile that includes our own PCI entitlement, but installed the driver on a machine with entitlement checks turned off.

Yep, that will work. It's not something I can really "recommend" (for obvious reasons), but it is intentional that this does work.

Moving to here:

I then tried making a USB driver for development (for a vendor ID we don't have an entitlement for). On my usual Mac, the driver won't load because the entitlement in my provisioning profile is for a specific vendor ID - I can't choose the development USB transport capability.

First, as a quick clarification, the term "capability" is basically a term Xcode invented for its own UI because what it's actually showing is a mix of:

  1. Entitlements
  2. Other "stuff" (like Info.plist keys) which are NOT in fact entitlements.

That second case doesn't really come up with DriverKit, but you can find one example of the confusion this creates (with some LLM help!) here.

Returning to specifics:

On my usual Mac, the driver won't load because the entitlement in my provisioning profile is for a specific vendor ID - I can't choose the development USB transport capability.

Were you using manual codesigning or automatic? The usual issue here is that automatic codesigning always chooses the development capability. That actually works pretty well, until developers try to ship a non-development build and Xcode starts falling apart.

If you're using automatic, try deleting the contents of your Entitlement.plist and then trying again. The development entitlements use a "*" to match "everything", but if you're manually tweaking your entitlement plist, you can create a "conflict" because the profile configuration and the entitlement configuration don't match.

One thing to keep in mind here is that Xcode's errors tend to "blame" in a way that can be misleading. So an error like "the provisioning profile doesn't match the app entitlements" reads as if the solution is to change the profile, but you could also fix the error by changing the entitlement plist.

Finally, what version of Xcode are you testing with? I haven't tested this in detail for a while, and it's possible something changed in the “latest" version.

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

and here are the bug numbers

FB19449747 No developer flavor of PCI transport capability
FB19450162 Two indistinguishable PCI transport capabilities shown
FB19450508 Xcode hides provisioning profiles
FB19451832 indistinguishable USB transport entitlements

also, to revert the changes you made to a victim machine:

sudo nvram boot-args -c

to clear all the boot-args.

sudo nvram boot-args --help

will tell you more then boot into recovery and perform

csrutil enable

to turn SIP on again

PCIDriverKit entitlements during development
 
 
Q