Classic confinement breaks high-dpi support

I noticed that sublime-text has broken high-dpi when invoked through snap run sublime-text.subl but not if invoked via /snap/sublime-text/current/opt/sublime-text/sublime_text

EDIT: To reproduce this you need to enable fractional scaling and set scaling to 125%.

This was puzzling because this snap uses classic confinement.

I debugged it to this operation, where wayland connection fails and fallback X connection is used:

13742 socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0) = 3
13742 connect(3, {sa_family=AF_UNIX, sun_path="/run/user/1000/snap.sublime-text/wayland-0"}, 45) = -1 ENOENT (Nie ma takiego pliku ani katalogu)
13742 close(3)                          = 0
13742 socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0) = 3
13742 connect(3, {sa_family=AF_UNIX, sun_path=@"/tmp/.X11-unix/X0"}, 20) = 0

As you can see, snap exec has altered XDG_RUNTIME_DIR and this prevents connection to the wayland socket from succeeding. I think we should not be doing that for classic confinement. For strict confinement this should work as well, but requires other approach.

CC @jdstrand
CC @kenvandine - this should be fixed for wayland in general

I’ve opened a quick RFC for classic confinement aspect of the bug https://github.com/snapcore/snapd/pull/7659/files

1 Like

The only reason we are setting XDG_RUNTIME_DIR from a security POV is to make it easier for applications to find their per-snap writable area in /run/user/1000/snap… I agree a classic snap doesn’t really need this, but the snap itself could fix this by using a wrapper to setup up the symlinks (ala desktop-launch) or reset XDG_RUNTIME_DIR. I’m hesitant to suggest changing XDG_RUNTIME_DIR for classic from within snapd since I fear it could break existing snaps and add developer friction when moving from classic to strict.

While I agree any change can break people I think we made a mistake by setting XDG_RUNTIME_DIR for classic confinement in the first place. If applications look for a socket that is not something as common as X or Wayland they will flat-out not work at all.

I’m not convinced it is the right decision for strictly confined snaps either. If you look through snapcraft-desktop-helpers or the newer snapcraft extension, we’ve got multiple multiple instances of symlinking sockets from the real XDG_RUNTIME_DIR to the private one in order for libraries to find their sockets (PulseAudio and Wayland).

Since we have per-user mount support now, an alternative would be to provide the snap with a private XDG_RUNTIME_DIR at the standard /run/user/$uid location. We could then bind mount in any sockets that the snap should have access to. Something like:

  • bind mount /run/user/$uid/snap.name to /run/user/$uid
  • touch /run/user/$uid/wayland-0 then bind mount /var/lib/snapd/hostfs/run/user/$uid/wayland-0 to that location (assuming snap has plugged wayland interface)
  • do the same for /run/user/$uid/bus if the snap should have access to the D-Bus session bus.
  • do the same for /run/user/$uid/pulse/native if the snap should have access to PulseAudio.
  • do the same for /run/user/$uid/doc (a directory rather than a file) if the snap has plugged desktop.

I’m worried about mounting sockets. They may come and go. I would much much rather use symlinks that point to either /run/user/UID/socket via hostfs or to …/socket if we use a sub-directory of the real directory instead.

The symlink stuff was never meant to be long term. It was the only option at the time due to how the wayland client and server discovered each other’s sockets (and, iirc, there were other options for pulse, we just did the same thing since it was easy and consistent). Once all the issues @zyga-snapd was found regarding mount namespace robustness are resolved, I think looking at @jamesh proposal makes sense. While it might be obvious, a couple things to add to @jamesh’ list is adjusting the apparmor policy to:

  • create /run/user/$uid/snap.name (we still do not; also all the directories needed in the previous list)
  • adjust apparmor policy to allow access to /run/user/$uid
1 Like

This branch was merged and will be soon available on the edge channel of both core and the snapd snaps but it is behind a feature flag. To enable this feature issue the following command:

snap set core experimental.classic-preserves-xdg-runtime-dir=true

Following this restart the affected application. Please report both success as well as issues in this thread.

I’ve proposed a PR to enable this by default now: https://github.com/snapcore/snapd/pull/9583

The feature can still be disabled if it causes issues on a specific system. Use this setting to do that:

snap set core experimental.classic-preserves-xdg-runtime-dir=false

To follow recommended defaults run:

snap unset core experimental.classic-preserves-xdg-runtime-dir