Some checks failed
Docker. / Ubuntu (push) Has been cancelled
User-agent updater. / User-agent (push) Failing after 15s
Lock Threads / lock (push) Failing after 10s
Waiting for answer. / waiting-for-answer (push) Failing after 22s
Needs user action. / needs-user-action (push) Failing after 8s
Can't reproduce. / cant-reproduce (push) Failing after 8s
Close stale issues and PRs / stale (push) Has been cancelled
120 lines
4.5 KiB
Markdown
120 lines
4.5 KiB
Markdown
# USB portal
|
|
|
|
The USB portal is the middleman between sandboxed apps, and the
|
|
devices connected and available to the host system. This is the first
|
|
version of the portal.
|
|
|
|
This part was implemented by
|
|
|
|
- Hubert Figuière
|
|
- Georges Basile Stavracas Neto
|
|
|
|
funded by the STF (Sovereign Tech Fund) effort, based upon initial
|
|
work by
|
|
|
|
- Ryan Gonzalez
|
|
|
|
and with help from other contributors.
|
|
|
|
## Device filtering
|
|
|
|
Sandboxed apps must declare which USB devices they support ahead of
|
|
time. This information is read by the XDG Desktop Portal and used to
|
|
determine which USB devices will be exposed to requesting apps. On
|
|
Flatpak, these enumerable and hidden devices are set by the `--usb`
|
|
and `--nousb` arguments against `flatpak build-finish` and `flatpak
|
|
run`. Neither `--devices=all` nor `--device=usb` do influence the
|
|
portal.
|
|
|
|
Hidding a device always take precedence over making them enumerable,
|
|
even when a blanket permission (`--usb=all`) is set.
|
|
|
|
However out of the sandbox we assume all devices are allowed as there
|
|
is no restriction that can prevent seeing anything.
|
|
|
|
Individual devices are assigned a unique identifier by the portal,
|
|
which is used for all further interactions. This unique identifier is
|
|
completely random and independent of the device. Permission checks are
|
|
in place to not allow apps to try and guess device ids without having
|
|
permission to access then.
|
|
|
|
## Permissions
|
|
|
|
There are 2 dynamic permissions managed by the USB portal in the
|
|
permission store:
|
|
|
|
1. Blanket USB permission: per-app permission to use any methods of
|
|
the USB portal. Without this permission, apps must not be able to do
|
|
anything - enumerate, monitor, or acquire - with the USB portal.[^1]
|
|
|
|
2. Specific device permission: per-app permission to acquire a
|
|
specific USB device, down to the serial number.
|
|
|
|
## Enumerating devices
|
|
|
|
There are 2 ways for apps to learn about devices:
|
|
|
|
- Apps can call the EnumerateDevices() method, which gives a snapshot
|
|
of the current devices to the app.
|
|
|
|
- Apps can create a device monitoring session with CreateSession()
|
|
which sends the list of available devices on creation, and also
|
|
notifies the app about connected and disconnected devices.
|
|
|
|
Only devices that the app is allowed to see are reported in both
|
|
cases.
|
|
|
|
The udev properties exposed by device enumeration is limited to a
|
|
well known subset of properties.[^2]
|
|
|
|
## Device acquisition & release
|
|
|
|
Once an app has determined which devices it wants to access, the app
|
|
can call the AcquireDevices() method. This method may prompt a dialog
|
|
for the user to allow or deny the app from accessing specific devices.
|
|
|
|
If permission is granted, XDG Desktop Portal tries to open the device
|
|
file on the behalf of the requesting app, and pass down the file
|
|
descriptor to that file.[^3]
|
|
|
|
The caller must then call FinishAcquireDevices() until it indicate it
|
|
is finished. It's only necessary to call it more than once if there
|
|
are too many file descriptors to return. This is a D-Bus
|
|
limitation. Check the `finished` return argument.
|
|
|
|
### Using the file descriptor
|
|
|
|
The file descriptors returned by the portal are meant to be used with
|
|
USB library you use.
|
|
|
|
In the case of libusb 1.0.23 and later, use `libusb_wrap_sys_device()`
|
|
and pass the file descriptor as the `sys_dev` argument. It should be
|
|
noted that libusb must be compiled with udev support (it is the
|
|
default) in order to be able to work. Without this it looks for the
|
|
non existant `/dev/usb` that is not present.
|
|
|
|
If you use libhidapi, you need to use the function
|
|
`hid_libusb_wrap_sys_device()` provided by libhidapi-usb.
|
|
|
|
---
|
|
|
|
[^1]: Exceptionally, apps can release previously acquired devices,
|
|
even when this permission is disabled. This is so because we don't yet
|
|
have kernel-side USB revoking. With USB revoking in place, it would be
|
|
possible to hard-cut app access right when the app permission changes.
|
|
|
|
[^2]: This patch uses a hardcoded list. There is no mechanism for apps
|
|
to influence which other udev properties are fetched. This approach is
|
|
open to suggestions - it may be necessary to expose more information
|
|
more liberally through the portal. The initial attempt has been made
|
|
to provide sensible information usefull for display in a user
|
|
interface.
|
|
|
|
[^3]: This is clearly not ideal. The ideal approach is to go through
|
|
logind's TakeDevice() method. However, that will add significant
|
|
complexity to the portal, since this logind method can only be called
|
|
by the session controller (i.e. the only executable capable of calling
|
|
TakeControl() in the session - usually the compositor). This can and
|
|
probably should be implemented in a subsequent round of improvements
|
|
to the USB portal.
|