flatpak / xdg-desktop-portal

Desktop integration portal
https://flatpak.github.io/xdg-desktop-portal/
GNU Lesser General Public License v2.1
585 stars 189 forks source link

xdg-desktop-portal does not transmit the application id on inhibit requests #963

Closed Cimbali closed 1 year ago

Cimbali commented 1 year ago

I’m using xdg-desktop-portal called somehow via GtkApplication.inhibit on OpenSUSE Tumbleweed (rolling release). The installed version for xdg-desktop-portal is 1.16.0


Inspecting the DBus shows that when an application requests xdg-desktop-portal to setup an inhibition:

method call time=1675813414.885762 sender=:1.449 -> destination=:1.6 serial=21 path=/org/freedesktop/portal/desktop; interface=org.freedesktop.portal.Inhibit; member=Inhibit
   string ""
   uint32 15
   array [
      dict entry(
         string "reason"
         variant             string "Fullscreen Presentation running"
      )
   ]

xdg-desktop-portal gathers information (here PID) about the requesting DBus id:

method call time=1675813414.886505 sender=:1.6 -> destination=org.freedesktop.DBus serial=1399 path=/org/freedesktop/DBus; interface=org.freedesktop.DBus; member=GetConnectionUnixProcessID
   string ":1.449"

method return time=1675813414.886533 sender=org.freedesktop.DBus -> destination=:1.6 serial=219 reply_serial=1399
   uint32 15889

Then it starts the impl interface, in my case xdg-desktop-portal-kde, registers a Request handle with it, and finally forwards the inhibit request with flags and reason, but without application id:

method call time=1675813414.890164 sender=:1.6 -> destination=:1.28 serial=1407 path=/org/freedesktop/portal/desktop; interface=org.freedesktop.impl.portal.Inhibit; member=Inhibit
   object path "/org/freedesktop/portal/desktop/request/1_449/t"
   string ""
   string ""
   uint32 15
   array [
      dict entry(
         string "reason"
         variant             string "Fullscreen Presentation running"
      )
   ]

The result is obviously that the battery widget displaying the inhibition can not display the application name or its icon:

battery applet with no application name nor icon

Currently the only workaround I’ve managed to find is to bypass xdg-desktop-portal completely, as e.g. Firefox does, by sending the request to org.freedesktop.ScreenSaver directly. This shows the desired result:

battery applet with Firefox name and icon

smcv commented 1 year ago

There are two cases that matter here: when the app is sandboxed (Flatpak, Snap or similar), or when the app is in the trusted computing base (from .deb, .rpm or similar).

  1. When the app is sandboxed, xdg-desktop-portal finds out which app it is by inspecting the app from the outside. This makes sure that there is no way for the app to lie to us, and say "I'm Firefox" when it's really some other app, in the hope that it can social-engineer the user into giving more permissions than it deserves.

  2. When the app is trusted, there is no secure way to find out which app it is (the app could lie to us) - although in this case, if the app is malicious, it could equally well subvert some unrelated app via ptrace or overwriting configuration files or something, and force that other app to do undesired things.

xdg-desktop-portal was originally designed to be used exclusively by sandboxed apps (scenario 2), but because some of the things it does are awkward to do any other way, it has started to be used by non-sandboxed apps (scenario 1) as well (either by the app itself, or by a library like GTK).

I think probably you are using trusted apps installed at OS level from a RPM, and therefore you are in scenario 2?

In the past we've been reluctant to include mechanisms in the API for the app to say "I know there's no way to verify this, but I claim that I'm Firefox, please believe me" because if we did, it would be very easy to have a vulnerability in xdg-desktop-portal or in a backend like xdg-desktop-portal-kde, where it trusts information that it should not, allowing a sandboxed Flatpak or Snap app to lie about its identity.

The way GNOME UIs have generally dealt with this is that if the verified app-ID is empty, they substitute some generic string like "An application". That's far from ideal, but it's also better than the KDE UI in your screenshots.

swick commented 1 year ago

Nowadays we do try to figure out the app id even from apps in the trusted base but that's a best-effort kind of thing and depending on how you started the application it might or might not work (e.g. https://github.com/bus1/dbus-broker/issues/302). IOW, how did you start the application?

Cimbali commented 1 year ago

The app was started via a KDE Applications menu launcher. I think that means something in kio like the ScopedProcessRunner. Note that if I start it as a command line from my terminal, then Konsole and its logo are displayed, so some apps are successfully looked up.

The level of trust can vary, it is a python app that can be distributed via rpm (quite trusted) or pip (user install so less trusted? and have its desktop file in $XDG_DATA_HOME/applications/). But both use cases not containerised.

It’s purely a UI rather than permissions issue though, as any app can call the Inhibit method. I suppose it still leaves space for apps to be dishonest and disguise their inhibition as that of another possibly more legitimate application.

I’ve recently done a PR for Mozilla VPN that identifies applications launched in KDE based on the sourcePath property (full path to desktop file), as all the info is in the cgroup and query-able (see mozilla-mobile/mozilla-vpn-client#1869 and mozilla-mobile/mozilla-vpn-client#5279). That may be of use though it only applies to KDE.

smcv commented 1 year ago

The level of trust can vary, it is a python app that can be distributed via rpm (quite trusted) or pip (user install so less trusted?)

If there is no mechanism to prevent the Python app from doing arbitrary things when run from pip, then it is trusted, by definition: in security jargon, a trusted component is a component that is technically able to break your security policy. This Python app could overwrite ~/.bashrc with malicious code if it wanted to, for example.

By that definition, anything that is not restricted by some technical mechanism (a container, LSM rules, seccomp, a VM, ...) is trusted.

smcv commented 1 year ago

Note that if I start it as a command line from my terminal, then Konsole and its logo are displayed, so some apps are successfully looked up

Assuming that Konsole is another app in the trusted computing base (terminals generally are!), I think that means the code path mentioned in https://github.com/flatpak/xdg-desktop-portal/issues/963#issuecomment-1422852688 is working as intended for Konsole, at least.

swick commented 1 year ago

The app was started via a KDE Applications menu launcher. I think that means something in kio like the ScopedProcessRunner.

Had a quick look and it seems to generate the correct unit name for portals to pick it up. Either this is not used or the portal is somehow being stupid.

Cimbali commented 1 year ago

The desktop file name is pympress.desktop and the cgroup name is app-pympress-f2cc99056d704f99962d6e7400cbda63.scope (under /sys/fs/cgroup/user.slice/user-1000.slice/user@1000.service/app.slice ) -- I’m not sure if that’s the unit name you’re referring to?

Cimbali commented 1 year ago

Seems to be your regex:

https://github.com/flatpak/xdg-desktop-portal/blob/e35a230c1aab33d6f557ab48d1e39f40f2e6ae03/src/xdp-utils.c#L163-L173

It apparently requires the ApplicationID to contain at least 2 literal dots (.) in (.+?\\..+?\\..+?). I don’t know if thats per spec but I have at least 137 desktop files that do not have a single . in their basename:

> find /usr/share/applications/ -name \*.desktop -exec basename {} .desktop \; | grep -Fv .  | wc -l
137
> find /usr/share/applications/ -name \*.desktop -exec basename {} .desktop \; | grep -Fv . | shuf | head
systemsettings
notification-daemon
kcm_launchfeedback
kcm_trash
kcm_nightcolor
libreoffice-impress
kcm_powerdevilprofilesconfig
kcm_splashscreen
konsolesu
jupyter-notebook

I can also confirm that renaming my desktop file to io.github.pympress.desktop fixes the issue for me.

swick commented 1 year ago

It apparently requires the ApplicationID to contain at least 2 literal dots (.) in (.+?\..+?\..+?). I don’t know if thats per spec but I have at least 137 desktop files that do not have a single . in their basename:

Yeah, no, it's not required per spec so we should lift that restriction.

swick commented 1 year ago

964

swick commented 1 year ago

Should be fixed now with #964.

GeorgesStavracas commented 1 year ago

Fixed by #964