Page MenuHomeFreeBSD

libusb: capsicumize libusb
Needs ReviewPublic

Authored by aokblast on Aug 11 2025, 3:54 PM.
Tags
None
Referenced Files
Unknown Object (File)
Mon, Jul 13, 1:19 PM
Unknown Object (File)
Sat, Jul 11, 8:27 PM
Unknown Object (File)
Thu, Jul 9, 11:11 AM
Unknown Object (File)
Tue, Jul 7, 3:48 AM
Unknown Object (File)
Mon, Jul 6, 9:12 PM
Unknown Object (File)
Sun, Jul 5, 7:32 AM
Unknown Object (File)
Thu, Jun 25, 4:40 PM
Unknown Object (File)
Thu, Jun 25, 3:27 PM

Details

Reviewers
jfree
pjd
markj
oshogbo
lwhsu
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 66192
Build 63075: arc lint + arc unit

Event Timeline

tools/tools/usbtest/usb_msc_test.c
970

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
644

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
644

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
904

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.

644

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
125

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
281–282

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
2060

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.

2100

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
650

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.

659

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.

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