Couldn't read USB device endpoints on MacOS15.3

Hi Folks,

We are reading the USB device data from our app using libusb/iokit libraries.

Before updating the MacOS to the 15.3 we never faced any issue but after updating OS to 15.3 Sequoia we started facing issue to access the USB device's information.

We are not getting the device endpoints for the matching service and fails with below error-

Error:Failed to create IOUSBHostObject. with reason: IOServiceOpen failed.

Respective code snippet-

service = IOServiceGetMatchingService(kIOMasterPortDefault, matchingDictionary);
IOUSBHostInterface* interface = [[IOUSBHostInterface alloc] initWithIOService:service
                                                                                  options:IOUSBHostObjectInitOptionsDeviceCapture
                                                                                    queue:*queue
                                                                                    error:&error
                                                                          interestHandler:nil];

We get the denial message during accessing the IOService

error	23:17:30.691934-0800	kernel	41 duplicate reports for Sandbox: spotlightknowledged(1399) deny(1) mach-lookup com.apple.diagnosticd
error	23:17:30.691945-0800	kernel	System Policy: com.prograde.pgdrefreshpro.helpe(70515) deny(1) iokit-open-service IOUSBHostInterface

Also when we checked the IOUSBHOST logs we can see pipes are stalled while running the RefreshPro app as below-

2025-02-05 22:06:31.838141-0800 0x25913e Error   0x0         0   0  kernel: (IOUSBHostFamily) AppleUSBIORequest: AppleUSBIORequest::complete: device 8 (SD PG05.5@08210000) endpoint 0x00: status 0xe0005000 (pipe stalled): 0 bytes transferred

We need an assistance here to know what exactly could be the cause and how can we elevate the permissions to access the USB device on MacOS15.3.

Do we need other entitlements? As we never faced such issue with our certificate and Identifier on any MacOS versions and with the current entitlements we have.

Do we need to include any entitlement in the code?

Thanks.

Answered by DTS Engineer in 826549022

We spent some time to create a provisioning profile which contains all these entitlements but are struggling here.

Sorry about that, this was my mistake. Quinn reminded me that the "com.apple.security.*" macOS entitlements are unrestricted, which means they're just added directly to the executable entitlements and are not included in the provisioning profile

So, going back to the beginning of things, I have a new guess as to what's going on here. The "core" error here is the kernel denying access:

2025-02-18 16:53:39.489770+0530 kernel: (Sandbox) System Policy: <bundle ID> (16293) deny(1) iokit-open-service IOUSBHostInterface

Looking more closely at things, I think this could be a side effect of some additional hardening we added specifically around mass storage access. A few things to try:

  • Google Chrome has a user client attached to IOUSBHostDevice and, for testing purposes, I would recommend removing Chrome and ensuring the user client is gone (you can see it in the IORegistry). I don't think it's a direct factor here, but I've also seen many cases where time ended up being wasted because a side factor like this ended up distorting the testing process.

  • There's a side complication here about how your helper tool is launched and how it gets correct access. For the time being, I would ignore that issue entirely and do your testing directly with in a "standard" app (not a helper tool). Once it's sorted out in that context, then you can figure out how to get the helper working.

Focusing on the that standalone test app, try the following:

  1. Add the NSRemovableVolumesUsageDescription to your test app and see if your user client access triggers the volume dialog and corrects the issue.

  2. If the dialog doesn't trigger, try directly accessing a file on the volume while it's mounted (I would just hard code the path), then unmounting the volume and opening the client.

  3. If the dialog doesn't trigger in #2 and/or the file access fails, then I would try using a open panel to select any object in the volume, then unmount and try opening the user client.

  4. Give you app Full Disk Access (FDA) and try opening the user client.

Returning to your helper tool, getting it working will depend on which test above succeeds and exactly how your tool is launched. In the simplest case (#1 or #2), then it may be enough to just add NSRemovableVolumesUsageDescription to the main app and TCC allowing your helper tool to inherit. However, it's also possible that you'll need to put your helper tool into an app bundle so that it can include it's own NSRemovableVolumesUsageDescription.


Kevin Elliott
DTS Engineer, CoreOS/Hardware

We are reading the USB device data from our app using libusb/iokit libraries.

As a side note, I'd strongly recommend moving to the IOUSBHost framework. It's been around for several years and, frankly, it's a far nicer API that the old IOUSBLib.

Looking at the specific failure:

error	23:17:30.691945-0800	kernel	System Policy: com.prograde.pgdrefreshpro.helpe(70515) deny(1) iokit-open-service IOUSBHostInterface

I'm not sure what actually changed here, but the "com.apple.security.device.usb" entitlement should bypass that failure.

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

Would it help if we share some logs? If yes, can you recommend any specific command we should run to fetch the logs?

Please file a bug on this and, as part of that bug, include the following:

  • Note the details of the hardware you're working with.

  • Collect an IORegistryExplorer.app snapshot and upload it to the bug.

  • Reproduce the issue you're seeing multiple times, noting exactly what times you'd triggered the issue in each test.

  • Collect a sysdiagnose and upload it to the bug.

...then post the bug number back here. Once the bug is filed and the data uploaded, I can pull the data from there and see what I can determine.

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

Hi Kevin,

Thanks for looking into this!

We have filed a bug with the relevant information. Bug link- https://feedbackassistant.apple.com/feedback/16517632

Please let us know if you require any other information around this.

Thanks.

We have filed a bug with the relevant information. Bug link- https://feedbackassistant.apple.com/feedback/16517632

Looking at the log data, it looks like you're missing the com.apple.security.device.usb entitlement. Does you helper process include it and have you tried adding it?

2025-02-18 16:53:39.489770+0530  0       kernel: (Sandbox) System Policy: helper tool processs> (16293) deny(1) iokit-open-service IOUSBHostInterface
2025-02-18 16:53:39.489850+0530  16293   <helper tool processs>: (IOUSBHost) Error:Unable to open io_service_t object and create user client. with reason: IOServiceOpen failed.
2025-02-18 16:53:39.489858+0530  16293   <helper tool processs>: (IOUSBHost) Error:Failed to create IOUSBHostObject. with reason: IOServiceOpen failed.
2025-02-18 16:53:39.489901+0530  16293   <helper tool processs>: (IOUSBHost) Error:Failed to create IOUSBHostInterface. with reason: Failed [super init]

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

Hi Kevin,

Yes, We have included the com.apple.security.device.usb entitlement and following are the details-

codesign -d --entitlements :- "Refresh Pro.app/Contents/Library/LaunchServices/com.prograde.pgdrefreshpro.helpertool"

Executable=/Applications/Refresh Pro.app/Contents/Library/LaunchServices/com.prograde.pgdrefreshpro.helpertool
warning: Specifying ':' in the path is deprecated and will not work in a future release
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "https://www.apple.com/DTDs/PropertyList-1.0.dtd"><plist version="1.0"><dict><key>com.apple.security.cs.allow-dyld-environment-variables</key><true/><key>com.apple.security.cs.allow-jit</key><true/><key>com.apple.security.cs.allow-unsigned-executable-memory</key><true/><key>com.apple.security.cs.disable-library-validation</key><true/><key>com.apple.security.device.usb</key><true/></dict></plist>```

codesign -d --entitlements :- "Refresh Pro.app/"

Executable=/Applications/Refresh Pro.app/Contents/MacOS/Refresh Pro
warning: Specifying ':' in the path is deprecated and will not work in a future release
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "https://www.apple.com/DTDs/PropertyList-1.0.dtd"><plist version="1.0"><dict><key>com.apple.security.cs.allow-dyld-environment-variables</key><true/><key>com.apple.security.cs.allow-jit</key><true/><key>com.apple.security.cs.allow-unsigned-executable-memory</key><true/><key>com.apple.security.cs.disable-library-validation</key><true/><key>com.apple.security.device.usb</key><true/></dict></plist>

Would it help if we share our dmg as well? Can you please share your email or any other way to send that?

Thanks.

Yes, We have included the com.apple.security.device.usb entitlement and following are the details-

Checking with "codesign" is only half of the validation process. Take a look at this forum post for a detailed walkthrough followed by an example of the output.

Would it help if we share our dmg as well? Can you please share your email or any other way to send that?

Assuming the validation shows the entitlement is properly applied, then please file a bug on this. As part of that bug, do the following:

  • Note the details of the hardware you're working with.
  • If possible, upload a copy of the build that's failing.
  • Collect an IORegistryExplorer.app snapshot and upload it to the bug.
  • Reproduce the issue you're seeing multiple times, noting exactly what times you'd triggered the issue in each test.
  • Collect a sysdiagnose and upload it to the bug.

...then post the bug number back here. Once the bug is filed and the data uploaded, I can pull the data from there and see what I can determine.

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

Hi Kevin,

Thanks for the links.

One thing to mention is that we are using electron js to bundle our app so the notarization process is managed by electron and we are not involving XCode directly.

We were missing a step where we were not embedding the provisioning profile in our app, so we created one with default entitlements using our developer account and downloaded that. Then we provided this provisioning profile and the entitlements to the electron build process which embedded the provisioning profile in our app. We also checked the provisioning profile with the commands provided in the link.

But, this is also not working for us. We have created a bug with our app's dmg and the provisioning profile.

Link: https://feedbackassistant.apple.com/feedback/16538455

FB16538455 (Contd: Couldn't read USB device endpoints on MacOS15.3)

Thanks again for looking into this.

We were missing a step where we were not embedding the provisioning profile in our app, so we created one with default entitlements using our developer account and downloaded that. Then we provided this provisioning profile and the entitlements to the electron build process which embedded the provisioning profile in our app. We also checked the provisioning profile with the commands provided in the link.

The app you uploaded to the bug is properly signed. The output of:

codesign -dvvv --ent :- <path>

Lists these entitlements:

<key>com.apple.security.cs.allow-dyld-environment-variables</key><true/>
<key>com.apple.security.cs.allow-jit</key><true/>
<key>com.apple.security.cs.allow-unsigned-executable-memory</key><true/>
<key>com.apple.security.cs.disable-library-validation</key><true/>
<key>com.apple.security.device.usb</key><true/></dict></plist>

While the output of:

security cms -D -i <path>/Contents/embedded.provisionprofile

Is this:

<key>Entitlements</key>
<dict>
			
			<key>com.apple.application-identifier</key>
	<string>__TEAM ID__.__BUNDLE ID___</string>
			
			<key>keychain-access-groups</key>
	<array>
			<string>__TEAM ID__.*</string>
	</array>
			
			<key>com.apple.developer.team-identifier</key>
	<string>__TEAM ID__</string>

</dict>

Once again, please take a look at this forum post for a detailed walkthrough followed by an example of the output.

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

Hi Kevin

We spent some time to create a provisioning profile which contains all these entitlements but are struggling here.

We tried 2 approaches.

1- Creating provisioning profile from developer account

  • In our developer account, we created a provisioning profile using our bundle id "com.prograde.pgdrefreshpro". In the "Entitlements" section we could find only 2 options

  • When we go to "Identifiers" and edit the Bundle ID we are using, we could see a list of capabilities we can enable. Which should we select for getting "com.apple.security.device.usb" entitlement in our provisioning profile? Will we have to request an entitlement here?

2- Selecting Automatic signing in XCode.

  • Since we were not using XCode for building our application, we created a dummy project.

  • We selected "App" under "Applications"

  • Then we provided the following details:

	"Product Name": pdgrefreshpro
	"Organization Identifier": "com.prograde"
	"Bundle Identifier": "com.prograde.pgdrefreshpro"
  • The project got created and we edited the pdgrefreshpro.entitlements as follows:
	<?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.cs.allow-jit</key>
			<true/>
			<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
			<true/>
			<key>com.apple.security.cs.allow-dyld-environment-variables</key>
			<true/>
			<key>com.apple.security.cs.disable-library-validation</key>
			<true/>
			<key>com.apple.security.device.usb</key>
			<true/>
			<key>com.apple.security.app-sandbox</key>
			<true/>
	</dict>
	</plist>
  • Then we went to "Signing & Capabilities" and selected "Automatically manage signing". But we are seeing "None Required" under "Provisioning Profile" section.

  • We also couldn't find the provisiong profile in this folder

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

Are we missing something here?

Thanks for your patience!

We spent some time to create a provisioning profile which contains all these entitlements but are struggling here.

Sorry about that, this was my mistake. Quinn reminded me that the "com.apple.security.*" macOS entitlements are unrestricted, which means they're just added directly to the executable entitlements and are not included in the provisioning profile

So, going back to the beginning of things, I have a new guess as to what's going on here. The "core" error here is the kernel denying access:

2025-02-18 16:53:39.489770+0530 kernel: (Sandbox) System Policy: <bundle ID> (16293) deny(1) iokit-open-service IOUSBHostInterface

Looking more closely at things, I think this could be a side effect of some additional hardening we added specifically around mass storage access. A few things to try:

  • Google Chrome has a user client attached to IOUSBHostDevice and, for testing purposes, I would recommend removing Chrome and ensuring the user client is gone (you can see it in the IORegistry). I don't think it's a direct factor here, but I've also seen many cases where time ended up being wasted because a side factor like this ended up distorting the testing process.

  • There's a side complication here about how your helper tool is launched and how it gets correct access. For the time being, I would ignore that issue entirely and do your testing directly with in a "standard" app (not a helper tool). Once it's sorted out in that context, then you can figure out how to get the helper working.

Focusing on the that standalone test app, try the following:

  1. Add the NSRemovableVolumesUsageDescription to your test app and see if your user client access triggers the volume dialog and corrects the issue.

  2. If the dialog doesn't trigger, try directly accessing a file on the volume while it's mounted (I would just hard code the path), then unmounting the volume and opening the client.

  3. If the dialog doesn't trigger in #2 and/or the file access fails, then I would try using a open panel to select any object in the volume, then unmount and try opening the user client.

  4. Give you app Full Disk Access (FDA) and try opening the user client.

Returning to your helper tool, getting it working will depend on which test above succeeds and exactly how your tool is launched. In the simplest case (#1 or #2), then it may be enough to just add NSRemovableVolumesUsageDescription to the main app and TCC allowing your helper tool to inherit. However, it's also possible that you'll need to put your helper tool into an app bundle so that it can include it's own NSRemovableVolumesUsageDescription.


Kevin Elliott
DTS Engineer, CoreOS/Hardware

Hi Kevin

Sorry for taking some time to respond, we were facing some notarization issues. That got resolved today. We tried adding the NSRemovableVolumesUsageDescription property key in our electron app. With this, it is working! We are getting a pop-up requesting file access after which, the deny error is no longer coming.

Thanks for pointing us to the right direction! Going forward, we'll be using this property key during our notarization. Thanks a lot for the help.

We'll do some more testing on our side and will let you know if we encounter any problems.

Couldn't read USB device endpoints on MacOS15.3
 
 
Q