Page MenuHomeFreeBSD

libusb: capsicumize libusb
Needs ReviewPublic

Authored by aokblast on Aug 11 2025, 3:54 PM.
Tags
None
Referenced Files
F166432662: D51865.diff
Thu, Aug 13, 1:29 PM
F166343805: D51865.id160587.diff
Thu, Aug 13, 12:51 AM
F166339407: D51865.id160193.diff
Thu, Aug 13, 12:20 AM
F166337004: D51865.id.diff
Thu, Aug 13, 12:02 AM
Unknown Object (File)
Wed, Aug 12, 2:16 PM
Unknown Object (File)
Wed, Aug 12, 1:33 PM
Unknown Object (File)
Wed, Aug 12, 1:17 AM
Unknown Object (File)
Wed, Aug 12, 12:14 AM

Details

Reviewers
jfree
pjd
markj
oshogbo
lwhsu
adrian
Group Reviewers
capsicum
Summary

FreeBSD's libusb has three components: libusb01, libusb10, and libusb20.

libusb20 handles communication with character devices. We now accept
file descriptors (FDs) for /dev/usb (usbd_fd) and /dev/usbctl (cfd)
directly, allowing users to open these and apply capabilities
themselves.

libusb10 is updated to support capabilities via a context option. Since
libusb allows general read/write access, we preserve all possible
capabilities when passing FDs to libusb20. It's the responsibility of
the libusb user to call cap_enter() at an appropriate time.

libusb01 is currently unused, so Capsicum support is not implemented for
it.

All base system tools using libusb20 have been updated to support
Capsicum.

Sponsored by: The FreeBSD Foundation

Diff Detail

Repository
rG FreeBSD src repository
Lint
Lint Passed
Unit
No Test Coverage
Build Status
Buildable 73824
Build 70707: arc lint + arc unit

Event Timeline

There are a very large number of changes, so older changes are hidden. Show Older Changes
tools/tools/usbtest/usb_msc_test.c
967–968

Is this just general unused variable cleanup? I tend to do these small unrelated cleanups in separate patches. This way, the small cleanup gets its own commit and stays if your bigger patch needs to be reverted for whatever reason.

usr.sbin/usbconfig/usbconfig.c
650

In the rest of your patch, you opened usbd_fd as a normal descriptor with O_RDONLY and now you're opening it as a directory descriptor. Maybe the rest of the usbd_fd open() calls should be updated to use O_PATH | O_DIRECTORY and I think you could eliminate most of the capabilities in your rights list for usbd_fd since I only see you using it for openat().

usr.sbin/usbconfig/usbconfig.c
650

The fd returns from the openat will inherit all of the capabilities from the fd pass to openat. Therefore, for the /dev/usb/*.*.* devices, we should give the usbd_fd, READ, WRITE, EVENT, IOCTL for later usage.

Good to see more Capsicumization efforts going on. I just had a few pedantic suggestions. Otherwise, this generally looks good.

lib/libusb/libusb.3
907–908

I'd add a .Xr capsicum 4 here since you're mentioning it earlier.

usr.sbin/usbconfig/usbconfig.c
48–49

These extern declarations aren't really doing anything since you declare both variables right below.

The extern declarations in dump.c should be enough. You could move them into a header and include that if you anticipate other source files needing to access them as well.

650

Oops, you're definitely right. Looks good to me then :)

Fix incorrect close fd for libusb

usr.sbin/usbconfig/usbconfig.c
48–49

You are right, I am too lazy:). Fix it now.

recover status when capsicum failed

hi!

So why are a whole lot of functions getting an fd added to them?

Do the FDs change during the runtime of the tool? Or are they something that could be set
once during some init phase (maybe in a new function which would call cap_enter, rather than
the owner having to call it) and then pulled out of some the libusb backend state?

kevans added inline comments.
lib/libusb/libusb.3
127

I'd maybe re-word this slightly to something like:

Prepare
.Nm
for operation within a sandbox.
Resources that will be needed for regular operation are pre-opened
with appropriate
.Xr rights 4
applied.
Note that it is users' responsiblity to call
.Fn cap_enter .

This implies a little more heavily that libusb is opening persistent resources.

lib/libusb/libusb.h
288

I'd maybe name it a more generic LIBUSB_OPTIOIN_SANDBOX; the libusb that everyone else uses could have platform-specific bits that are required to enable sandboxing with it.

hi!

So why are a whole lot of functions getting an fd added to them?

Do the FDs change during the runtime of the tool? Or are they something that could be set
once during some init phase (maybe in a new function which would call cap_enter, rather than
the owner having to call it) and then pulled out of some the libusb backend state?

IMO we really shouldn't have libraries entering capablity mode- libusb may be just one of many, and setting a precedence like that where some will insist on entering the sandbox is bound to end up with some really annoying circumstances.

hi!

So why are a whole lot of functions getting an fd added to them?

As we need to provide the require file descriptor that need to be opened before cap_enter.

Do the FDs change during the runtime of the tool? Or are they something that could be set
once during some init phase (maybe in a new function which would call cap_enter, rather than
the owner having to call it) and then pulled out of some the libusb backend state?

Yes, cap_enter is called in bhyve. The internal fd state is opaque to bhyve.

hi!

So why are a whole lot of functions getting an fd added to them?

Do the FDs change during the runtime of the tool? Or are they something that could be set
once during some init phase (maybe in a new function which would call cap_enter, rather than
the owner having to call it) and then pulled out of some the libusb backend state?

IMO we really shouldn't have libraries entering capablity mode- libusb may be just one of many, and setting a precedence like that where some will insist on entering the sandbox is bound to end up with some really annoying circumstances.

I can somehow agree with you. But how can we integrate to bhyve without this as bhyve is capsicumized by default? We can turn off temporary but it adds complexity on bhyve.

hi!

So why are a whole lot of functions getting an fd added to them?

Do the FDs change during the runtime of the tool? Or are they something that could be set
once during some init phase (maybe in a new function which would call cap_enter, rather than
the owner having to call it) and then pulled out of some the libusb backend state?

IMO we really shouldn't have libraries entering capablity mode- libusb may be just one of many, and setting a precedence like that where some will insist on entering the sandbox is bound to end up with some really annoying circumstances.

I can somehow agree with you. But how can we integrate to bhyve without this as bhyve is capsicumized by default? We can turn off temporary but it adds complexity on bhyve.

No, your approach is fine -- part of his suggestion was that libusb provides something that does these things and calls cap_enter itself as I read it, and that's something that I think should stay outside of libusb.

lib/libusb/libusb10.c
2042

Why do we need the caller to explicitly ask the library to be capsicum-safe? Can't it just always use capsicum-safe operations? During library initialization, have libusb open whichever /dev nodes it needs, and keep the descriptors saved in some context structure. Applications which use libusb shouldn't need to change.

2082

Suppose these fields are already set, i.e., LIBUSB_OPTION_CAPSICUMIZE was configured once already. Then the second time, the descriptors will be leaked.

tools/tools/usbtest/usbtest.c
844

Same comment as below about cleaning up.

848

The return value should be checked, see my comment below.

usr.sbin/usbconfig/usbconfig.c
656

Shouldn't the library tell you which rights are needed? The application doesn't really know, it's just treating the usb descriptors as an opaque handle.

665

This is main(), so when you return, the program exits. So, I don't think it's necessary to have all of this cleanup code to close file descriptors.

669
  • This should check for errors (the main one being that the kernel can be compiled without capsicum support).
  • Better to use caph_enter().
952

much better, yay! thanks!

This revision is now accepted and ready to land.Sat, Jul 25, 2:38 AM
lib/libusb/libusb20_ugen20.c
93

I think you need capiscum_helpers.h for this.

usr.sbin/usbconfig/usbconfig.c
583

dump_device_info()->_device_desc()->load_vendors() will try to open _PATH_LUSBVDB, and that'll fail in capability mode.

I think this is straightforward to deal with, just make sure usb_vendors is initialized before you enter capability mode.

lib/libusb/libusb20.h
308–309

There is some code under share/examples/libusb20 which uses these interfaces, it should be updated too.

Why is it okay to change the library ABI?

We'll need a so bump for libusb (see D55687, D55686) so we should coordinate to have all of these changes happen together.

lib/libusb/libusb20.h
308–309

Yes, we definately needs to merge ABI tagging back to fix it

This revision now requires review to proceed.Thu, Aug 13, 5:36 AM
markj added a subscriber: kib.

Mostly looks good to me.

lib/libusb/Symbol.map
258 ↗(On Diff #183962)

This is off by one. There is no FBSD_1.10 (yet), FBSD_1.9 is for symbols added in FreeBSD 16.0. See lib/libc/Versions.def.

The existing symbols should be in FBSD_1.8, not FBSD_1.9. It doesn't really matter in practice, I think, but I am not too knowledgeable on this topic. Maybe @kib can suggest whether it is worth fixing this.

share/examples/libusb20/bulk.c
229 ↗(On Diff #183962)

I am not sure it makes sense to enter capability mode in this example, but ok.

usr.sbin/usbconfig/dump.c
367

BTW, it is weird to malloc() this structure. It's just a STAILQ head, it can be defined globally with

static struct usb_vendors usb_vendors = STAILQ_INITIALIZER(&usb_vendors);

Then, just test STAILQ_EMPTY(&usb_vendors) to see if we need to read from the file.

469

Why does this need to be called? You are already calling it in main().

This revision is now accepted and ready to land.Thu, Aug 13, 2:34 PM
lib/libusb/libusb20.c
1325–1328

I think we should just switch to the new interface at the same time that we bump the so version.

Anyway. Thanks!

lib/libusb/Symbol.map
258 ↗(On Diff #183962)

I uses 1.9 originally as I see it is our latest symbols version. I am also not familier with our rule. Also, I have two questions now.

Is it too late to overwrite with 1.8? My patch for versioning libusb is landed earlier but I am not sure if it can be revoked?

If we want to change the symbol versioning. Would it be great to use libusb's own versioning? LUSB_1.0 or something like this. I see some libraries have their own versioning namespace.

usr.sbin/usbconfig/dump.c
367

I try to not change to much thing at the same time but you are right:). Wil be reflect in my final version.

469

Oh yes. Thanks for pointing this out. I will remove this.

lib/libusb/libusb20.c
1325–1328

Oh, yeah, it's not really important to provide compat here. Suppose this patch is committed today. Then, anyone who compiled libusb applications against main in the past 3 days will get backwards compat. It is not worth bothering.

usr.sbin/usbconfig/dump.c
367

Sorry, I didn't mean you should fix it in this patch, it's fine to defer it. Just something I noticed while reading.

lib/libusb/Symbol.map
258 ↗(On Diff #183962)

I think we have some leeway in main to make such a change if little time has elapsed; we'd just send a heads-up to the -current mailing list. But this is a bit of an odd case and I'd like to see what @kib suggests.

lib/libusb/Symbol.map
258 ↗(On Diff #183962)

We do need a place were we can fix ABI bugs., So yes, generally as far as something is not yet in a stable branch, we can tweak it.

WRT using the libusb-own schema for versioning namespaces, it would just cause anybody working on it to ask a guidance what to do there. IMO it is better to stuck with the common approach if technically possible.

lib/libusb/libusb20.3
993
lib/libusb/libusb20.c
1319

Isn't this if() pointless?

lib/libusb/libusb20.h
37

Why it does not use __BEGIN_DECLS etc?

Reflect markj@ and kib@'s comment

This revision now requires review to proceed.Thu, Aug 13, 3:58 PM

I have merged the 1.9 -> 1.8 patch to main first. Other things fixed. Thanks!

lib/libusb/libusb20.h
37

Will fix it in another patch. Thanks!

Now that the shlib version has been bumped we should be able to land D55687 without backwards compat symver. @bapt may not be around for a little while so someone (possibly me) might want to pick that up