Improving xdg-desktop-portal support

At GUADEC, I had a number of discussions about improving the snap support in xdg-desktop-portal. The primary shortcomings of what we currently have are:

  1. It uses AppArmor labels to detect snapped applications, so does not work correctly on distros that don’t enable AppArmor support.
  2. Portals APIs like notifications that depend on desktop file IDs do not function, since unlike Flatpaks, snap package names != desktop IDs.
  3. The document portal assumes snaps can not access any files on the host system, so will proxy all files. For Flatpaks, it avoids proxying files the snap can access directly.

We had a good idea of how to solve most of this in the past, but I had put off working on it since the current solution mostly worked and I had other tasks to deal with. Below is a more concrete sketch of what I think is needed based on those old ideas.

A snap-info command

We don’t want to introduce new dependencies to xdg-desktop-portal, since we want snap support to remain part of the default configuration with no incentive to try and disable it. So instead, the we will have xdg-desktop-portal invoke a snap subcommand to retrieve the info it needs in a machine readable format.

The exact command name is TBD, but lets pick snap internal snap-info as a placeholder. As for the machine readable format, I think ini/keyfile format would be the best option: there is a parser for it in glib, and the portal service does not currently depend on any json or yaml parsers. It is also extensible, making it easy to expose more information in future that can be ignored by old versions of the portal software.

The command will be invoked with a process ID as an argument, and output something like the following:

[Snap Package]
InstanceName=<snap package name>
Network=<true/false> # if the network plug is connected
DesktopFile=<desktop file ID>

I expect all of this information can be provided using the existing snapd APIs, so this would only involve changes to the snap command. It would look roughly like this:

  1. determine the snap name by checking the freezer cgroup membership in /proc/$pid/cgroup.
  2. Request information about the snap from snapd.
  3. Request connection status of network plug from snapd.
  4. Determine the associated desktop file ID:
    • Check /proc/$pid/attr/current to see if we’re confined by AppArmor. If so, use the label to determine which app within the snap we’re talking to, and return its desktop file.
    • As a fallback, pick the first desktop file returned by snapd. (can we do better?)

File access check

The document portal currently calls out to the flatpak info command to determine file access. I suggest we follow the same API, with something like:

snap internal snap-info --file-access=$path $snap_nape

This would then print one of the following: hidden, read-only, or read-write. False negatives are fine here (it would just result in more files being proxied via the document portal). So I think the following rules would be sufficient for a first pass:

  1. check if the snap is using classic confinement: if so, always return read-write.
  2. if the snap has the home interface connected, return read-write for non-hidden paths in the user’s home directory.
  3. return read-write for $SNAP_USER_DATA, $SNAP_USER_COMMON, $SNAP_DATA and $SNAP_COMMON.
  4. otherwise return hidden.

This will return read-write for files the user can’t write to due to file system permissions, but I think this is the right choice: we won’t be able to turn them into writable paths by proxying them through the document portal.

1 Like

Not sure you considered this, but for systems with apparmor enabled, you could also use the libapparmor query api to determine if a file is allowed by the currently loaded policy. Note that apparmor would be unaware of the mount namespace, so would have to consider things like /tmp separately.

I remember using that API back in the Ubuntu Phone days when working on the storage-framework service. Back then, it couldn’t handle @owner based access grants. Has that changed?

Given that we’ll need something that will work for the no-AppArmor case, and our heavy use of mount namespaces is liable to generate false positives, it might be more trouble than its worth.

No: (thanks for the reminder about owner match not working right with the query interface).

1 Like

Up to naming (some of the information seems portal specific so maybe the command name should have portal in it) and details, it seems ok as proposal.

1 Like