xdg-desktop-portal
xdg-desktop-portal copied to clipboard
Add USB device access portal
TBD
the way forward for these is for some application that needs these devices to step up and get a design for a portal, propose a portal api, and implement it. I'm happy to assist with these steps, but I'm unlikely to produce more portals all by myself without concrete involvement from api consumers.
the way forward for these is for some application that needs these devices to step up and get a design for a portal, propose a portal api, and implement it. I'm happy to assist with these steps, but I'm unlikely to produce more portals all by myself without concrete involvement from api consumers.
I'm getting the process started now.
Prior art
-
iOS "External Accessory" framework: https://developer.apple.com/documentation/externalaccessory https://developer.apple.com/library/archive/featuredarticles/ExternalAccessoryPT/Introduction/Introduction.html#//apple_ref/doc/uid/TP40009502
-
Android USB host overview: https://developer.android.com/guide/topics/connectivity/usb/host
-
USB device access for Chrome Apps: https://developers.chrome.com/apps/app_usb
On iOS, a device will declare which protocols it speaks (less "USB mass-storage" and more com.Hwmanufacturer.MassStorage
), and apps will list which protocols they support. Whether apps are allowed to enumerate those devices is gated through the App Store, whether an app can access a specific device is done at the OS level ("App blah wants to access foo").
On Android, the process is similar. The application must declare which devices (USB vendor and product IDs), or which class/subclass (all headsets, all mass-storage devices) ahead of time, in its manifest. Enumeration is allowed within those boundaries, authorisation to access is then requested. It seems that Android doesn't handle only allowing certain endpoints to be accessed.
Chrome OS/Chrome Apps works similarly to Android.
Draft design
-
supported devices get listed in the Flatpak manifest, or in a separate file shipped in the Flatpak. We need to be able to access it from outside the sandbox to show it somewhere like the Privacy settings panel, or GNOME Software. This avoids applications being able to fingerprint users and devices.
-
add a portal that uses that device list, and filters out the rest of the devices for enumeration. This doesn't require authentication.
-
add a portal to open a particular device. If the enumeration is filtered on interface class, disallow claiming any interface but the one that was filtered on. This would trigger an authorisation dialogue. Ideally, the portal would be able to open devices without needing them to be accessible by the user itself. Do we want to make this a polkit authorisation instead of a Portal-level one? Do we also want to allow kernel drivers to be detached?
-
modify libusb to use that portal when run inside a flatpak
-
add a per-app toggle to allow/disallow USB access, which would just make libusb say that there's no supported devices.
For listing the usb devices supported, maybe we can use the --add-policy=SUBSYSTEM.KEY=VALUE
generic flatpak permissions. These are copied into the metadata file and will be accessible in /.flatpak-info for the running instance.
However, i'm not sure how this prohibits fingerprinting? Surely you can just list a shitload of devices? Would make the finger-printer more obvious though...
For the per-app permissions, we can store those in the permissions store.
Other than that, this sounds like a plan to me, but the devil is gonna be in the details.
For listing the usb devices supported, maybe we can use the
--add-policy=SUBSYSTEM.KEY=VALUE
generic flatpak permissions. These are copied into the metadata file and will be accessible in /.flatpak-info for the running instance.
Ideally, this would be imported into the manifest by flatpak-builder, so that we can have the applications programmatically list those identifiers during the build. A static list inside the manifest is probably fine if you support a single type of device, or just a few devices, but that list could get long (in the tens) pretty easily.
However, i'm not sure how this prohibits fingerprinting? Surely you can just list a shitload of devices? Would make the finger-printer more obvious though...
You'd need to list about 130k items if you wanted to list every possible VID:PID combinations. The user or the repository owner would surely notice.
For the per-app permissions, we can store those in the permissions store.
OK.
Other than that, this sounds like a plan to me, but the devil is gonna be in the details.
As always :)
You'd need to list about 130k items
Sorry, it's about 4 billion :)
Slightly offtopic but with the potential of simplifying the implementation, recently device namespaces support made it into the kernel (so a privileged process with CAP_SYS_ADMIN can tag uevents and send to the correct network namespace owned by a user namespace) and then the device manager running inside that or just a little process listening for those could act accordingly. I don't know if this is useful for the portals implementation but I guess this might be interesting for, say, systemd, which could grow support to expose this to other users as some API that flatpak could benefit from. Ignore if this is irrelevant (perhaps this could be something flatpak developers can discuss with Lennart and work something out that is useful for everyone now that newer kernels support it).
As an example, libgphoto2 has a set of udev rules and a script to properly setup permission on the devices with udev
(on Fedora it is these two files):
/usr/lib/udev/check-ptp-camera
/usr/lib/udev/rules.d/40-libgphoto2.rules
Maybe we could provide a similar mechanism for the portal to determine which devices should be granted permission. With libgphoto2 the library is in the flatpak so this generated list could be used for the policy,
Maybe we could provide a similar mechanism for the portal to determine which devices should be granted permission. With libgphoto2 the library is in the flatpak so this generated list could be used for the policy,
Sorry, I don't understand to what that "mechanism" would be similar. udev permissions aren't usable or reliable for sandboxed applications, as applications can't rely on the host side having updated libraries and data files to give them access to devices, or the necessary updated libraries to detect devices at runtime (especially if that requires talking to the devices).
Slightly offtopic but with the potential of simplifying the implementation, recently device namespaces support made it into the kernel (so a privileged process with CAP_SYS_ADMIN can tag uevents and send to the correct network namespace owned by a user namespace) and then the device manager running inside that or just a little process listening for those could act accordingly.
udev events are not usable inside a sandbox as the kernel/user-space API and ABI is purposefully not designed to be forward or backwards compatible. Even if it were, filtering is done on the user-space side, so would leak information to the sandboxed application, and that would still leave the problem of device access (rather than device discovery).
Strongly related to supporting U2F/WebAuthn via USB, see: https://github.com/flatpak/xdg-desktop-portal/issues/989
Sorry, I don't understand to what that "mechanism" would be similar. udev permissions aren't usable or reliable for sandboxed applications
I don't think they asking for udev support per se, but for something that can give flatpak applications the ability to change the permissions of a USB device.
Due to the current limitations of flatpak, it is not possible to connect a real Wii Remote to the Dolphin emulator, unless you make a udev
rule.
https://github.com/flathub/org.DolphinEmu.dolphin-emu/issues/44
It would be nice to have an API that can allow the user to change the permission of the device. So stuff, like the Wii Remote, can work out of the box.
Prior art
* iOS "External Accessory" framework: https://developer.apple.com/documentation/externalaccessory https://developer.apple.com/library/archive/featuredarticles/ExternalAccessoryPT/Introduction/Introduction.html#//apple_ref/doc/uid/TP40009502 * Android USB host overview: https://developer.android.com/guide/topics/connectivity/usb/host * USB device access for Chrome Apps: https://developers.chrome.com/apps/app_usb
On iOS, a device will declare which protocols it speaks (less "USB mass-storage" and more
com.Hwmanufacturer.MassStorage
), and apps will list which protocols they support. Whether apps are allowed to enumerate those devices is gated through the App Store, whether an app can access a specific device is done at the OS level ("App blah wants to access foo").On Android, the process is similar. The application must declare which devices (USB vendor and product IDs), or which class/subclass (all headsets, all mass-storage devices) ahead of time, in its manifest. Enumeration is allowed within those boundaries, authorisation to access is then requested. It seems that Android doesn't handle only allowing certain endpoints to be accessed.
Chrome OS/Chrome Apps works similarly to Android.
Draft design
* supported devices get listed in the Flatpak manifest, or in a separate file shipped in the Flatpak. We need to be able to access it from outside the sandbox to show it somewhere like the Privacy settings panel, or GNOME Software. This avoids applications being able to fingerprint users and devices. * add a portal that uses that device list, and filters out the rest of the devices for enumeration. This doesn't require authentication. * add a portal to open a particular device. If the enumeration is filtered on interface class, disallow claiming any interface but the one that was filtered on. This would trigger an authorisation dialogue. Ideally, the portal would be able to open devices without needing them to be accessible by the user itself. Do we want to make this a polkit authorisation instead of a Portal-level one? Do we also want to allow kernel drivers to be detached? * modify libusb to use that portal when run inside a flatpak * add a per-app toggle to allow/disallow USB access, which would just make libusb say that there's no supported devices.
Hi hadess, I am trying to move forward with issue 227 of xdg-desktop-portal, I'm analyzing how to modify libusb so that it verifies if it is running from flatpak or not. What method do you suggest to do it? I'm not sure that validating via dbus is the best option.
Thank you.
I'm analyzing how to modify libusb so that it verifies if it is running from flatpak or not. What method do you suggest to do it?
The existing APIs check for the existence of /.flatpak-info
within the container.
g_file_test ("/.flatpak-info", G_FILE_TEST_EXISTS);
Hi hadess, I am trying to move forward with issue 227 of xdg-desktop-portal, I'm analyzing how to modify libusb so that it verifies if it is running from flatpak or not. What method do you suggest to do it? I'm not sure that validating via dbus is the best option.
Checking for /.flatpak-info
is the best thing to do.
After that I think that the code in the client libusb will need to use D-Bus to get a file descriptor from the portal, and use something like libusb_wrap_sys_device()
to open it as a device. Which means you can probably start working on an proof-of-concept by writing a test application that enumerates using the portal, and then opens the device through the portal, and see if libusb can still communicate with the device.
The main problem you're going to run into is device node ownership. Just chmod
/chown
the device node for now, until we figure out how that section would need to be implemented.
Hi hadess, I am trying to move forward with issue 227 of xdg-desktop-portal, I'm analyzing how to modify libusb so that it verifies if it is running from flatpak or not. What method do you suggest to do it? I'm not sure that validating via dbus is the best option.
Checking for
/.flatpak-info
is the best thing to do.After that I think that the code in the client libusb will need to use D-Bus to get a file descriptor from the portal, and use something like
libusb_wrap_sys_device()
to open it as a device. Which means you can probably start working on an proof-of-concept by writing a test application that enumerates using the portal, and then opens the device through the portal, and see if libusb can still communicate with the device.The main problem you're going to run into is device node ownership. Just
chmod
/chown
the device node for now, until we figure out how that section would need to be implemented.
Thank you very much for your responses hadess and felipeborges.
Could I add as an extra condition that the process with id 1 is bwrap? to make sure it's really running from flatpak?
Thank you.
Hi @5mdlc, I was wondering how is it going with this issue? Let me know if I can help you out, I'm quite interested on this too.
Hi @5mdlc, I was wondering how is it going with this issue? Let me know if I can help you out, I'm quite interested on this too.
Hi victortoso, at this moment, i have in pause this project, but you can to fork project and advance, any question you do have, i will pleasure to answer.
Since this seems to still be unclaimed, I've started work on this, inspired by a mix of the current udev APIs and Android's permissions design.
One quick question: should this be part of the current device portal API or a different one (i.e. org.freedesktop.portal.Usb
)? Right now I'm doing the former (extending the current API), but it would be pretty trivial to switch to the latter if preferred.
Since this seems to still be unclaimed, I've started work on this, inspired by a mix of the current udev APIs and Android's permissions design.
We need revoke support for USB first...
@refi64 Any update regarding your implementation? It is still not possible to use SDRs and other specific hardware with Flatpak apps because such devices almost always require custom udev rules to be installed (they work fine with Flatpak'ed SDR software after copying their udev rules manually into host /etc/udev
). It would be great to have this working in Flatpak (at least as a portal to add/remove custom udev rules into the system).
After that I think that the code in the client libusb will need to use D-Bus to get a file descriptor from the portal, and use something like
libusb_wrap_sys_device()
to open it as a device. Which means you can probably start working on an proof-of-concept by writing a test application that enumerates using the portal, and then opens the device through the portal, and see if libusb can still communicate with the device.The main problem you're going to run into is device node ownership. Just
chmod
/chown
the device node for now, until we figure out how that section would need to be implemented.
This might be of interest, I worked on a usbredir system helper recently: https://gitlab.freedesktop.org/elmarco/usbredir-rs/-/blob/main/usbredir-helper/src/main.rs
It opens the device, checking policykit permissions and hands off the device fd to the caller. Then libusb these days can wrap it. (some older libusb version couldn't do that, and spice-client-glib-usb-acl-helper
did change device permissions, which could be problematic)
Another things that in many cases need custom udev rules are VR headsets.
It is still not possible to use SDRs and other specific hardware with Flatpak apps because such devices almost always require custom udev rules to be installed (they work fine with Flatpak'ed SDR software after copying their udev rules manually into host /etc/udev).
Another things that in many cases need custom udev rules are VR headsets.
Why can't those rules be upstreamed?
We've recently upstreamed rules to access media* nodes, protocol analysers and there's work on doing that for music production hardware. If things can't be upstreamed, there needs to be a reason, and SDR doesn't strike me as something security sensitive.
This might be of interest, I worked on a usbredir system helper recently: https://gitlab.freedesktop.org/elmarco/usbredir-rs/-/blob/main/usbredir-helper/src/main.rs
Something like this might work if it were something that libusb or systemd shipped directly. I would expect another layer or checking for allowed devices in a typical desktop use case (eg. not being able to have raw access to network or Bluetooth devices).
It is not always possible to ship these rules upstream. For example, the RTL based SDRs also work as DVB-T cards and some people use them this way. But after installing these SDR rules, they start working as SDR instead. On a regular GNU/Linux distro, these rules are installed as a part of a SDR software (and uninstalled when removing the software), but it can be done this way with Flatpak. And there are many other examples where it is not possible to ship the udev rules as a part of systemd/udevd.
edit: Looks like I was wrong and it actually is possible to ship these rules upstream (they do not contain any blacklists and do not break anything as mentioned in https://github.com/flatpak/xdg-desktop-portal/issues/227#issuecomment-961224458. Thanks!
For example, the RTL based SDRs also work as DVB-T cards and some people use them this way. But after installing these SDR rules, they start working as SDR instead. On a regular GNU/Linux distro, these rules are installed as a part of a SDR software (and uninstalled when removing the software), but it can be done this way with Flatpak.
By upstream, I meant definitely meant systemd. For DVB-T/SDR cards, just like for protocol analysers, there's nothing much to be broken by giving the user at the computer full access to the device, in a desktop setting. You would expect that to be blocked off on an appliance, not on a general-purpose computer.
I understand that this solution doesn't work for every type of device, but we need to start fixing problems upstream when they can be.
This is how the RTL-SDR rules do look like. I always thought that they also blacklisted the original kernel modules and did other things needed to make the RTL2832 devices work as an SDR. But it looks like that they don't. Maybe it is not needed anymore? Anyway, I have filled a ticket for upstreaming the udev rules here. I have also filled the same ticket for a similar SDR called Airspy here. Thanks for pointing this out! :-)
Regarding the VR headsets, various game controllers and other hardware devices that are shipped with Steam. @smcv Are there any plans to upstream (some of) these rules (into the systemd)?
Regarding the VR headsets, various game controllers and other hardware devices that are shipped with Steam. @smcv Are there any plans to upstream (some of) these rules (into the systemd)?
It's on my list, but it's a long list.
The main blocker is that I need to talk to Steam and Wine/Proton developers and write down a justification for why they need to access these devices with raw HID, as opposed to evdev.