How can a confined snap run other snaps (or applications)?

Thanks for asking all the right questions. To an extend I’ve been exploring this problem space by seeing how far I can get, fixing the next pain point and iterating. My instinct at this point is to go for the simplest set of requirements that might possibly be usable and reassess after that.

A simple, confined desktop

A confined graphical shell that launches other snaps based on /var/lib/snapd/desktop/applications provides a lot of flexibility. (In a classic environment it would even allow “classic” snaps to be run and arbitrary execution from there.)

As you say, reading this directory should just be an AppAmor rule. But that’s just the start.

Executables or .desktop files

Sticking to desktop files avoids a slippery slope that leads to something like execvpe() and passing file descriptors.

It just leaves the questions of how to pass any % arguments used in Exec and what interprets the .desktop contents. (I see xdg-open in the Launcher source, but, to the Internet’s surprise xdg-open doesn’t understand .desktop files - a shame as otherwise they could be passed to OpenURL.)

I guess a first iteration could simply the Exec line and exec that. (Which is what I do in egmde currently.)

Icons

Currently, as you observer, icon’s won’t work (and are already broken on some distros):

$ grep Icon= /var/lib/snapd/desktop/applications/*.desktop 
/var/lib/snapd/desktop/applications/cevelop_cevelop.desktop:Icon=/snap/cevelop/x1/icon.xpm
/var/lib/snapd/desktop/applications/classic-snap-analyzer_classic-snap-analyzer.desktop:Icon=/snap/classic-snap-analyzer/5/meta/gui/classic-snap-analyzer.png
/var/lib/snapd/desktop/applications/clion_clion.desktop:Icon=/snap/clion/81/bin/clion.png
/var/lib/snapd/desktop/applications/gnome-calculator_gnome-calculator.desktop:Icon=/snap/gnome-calculator/406/meta/gui/org.gnome.Calculator.svg
/var/lib/snapd/desktop/applications/gnome-characters_gnome-characters.desktop:Icon=/snap/gnome-characters/296/meta/gui/org.gnome.Characters.svg
/var/lib/snapd/desktop/applications/gnome-logs_gnome-logs.desktop:Icon=/snap/gnome-logs/61/meta/gui/org.gnome.Logs.svg
/var/lib/snapd/desktop/applications/gnome-system-monitor_gnome-system-monitor.desktop:Icon=/snap/gnome-system-monitor/100/meta/gui/org.gnome.SystemMonitor.svg
/var/lib/snapd/desktop/applications/inkscape_inkscape.desktop:Icon=/snap/inkscape/4693/share/inkscape/branding/inkscape.svg
/var/lib/snapd/desktop/applications/multipass_multipass-gui.desktop:Icon=/snap/multipass/1002/meta/gui/multipass-gui.svg
/var/lib/snapd/desktop/applications/vlc_vlc.desktop:Icon=/snap/vlc/1049/usr/share/icons/hicolor/256x256/apps/vlc.png

I’m going to declare that “out of scope” for the current discussion. if a standard location materializes then it becomes easy.

Environment variables to launch desktop apps

The only successfully confined desktop environment I know of is egmde-confined-desktop. In this, the environment variables are not available in the host user environment (if any).

Variable Source Comment
XDG_RUNTIME_DIR Set by snapd on classic, different to the user session
WAYLAND_DISPLAY Set by egmde when launching an app
DISPLAY This snap doesn’t enable X11 apps Would set by egmde when launching an app
XDG_RUNTIME_DIR and WAYLAND_DISPLAY

We need a way to map the file $XDG_RUNTIME_DIR/$WAYLAND_DISPLAY in requesting context to $XDG_RUNTIME_DIR/$WAYLAND_DISPLAY in the application context.

There’s discussion elsewhere (Wayland interface, $XDG_RUNTIME_DIR and connecting clients to server) about managing XDG_RUNTIME_DIR. (WAYLAND_DISPLAY ought to be considered there too, but is assumed to be unset). If we assume that both server and client snaps do the “dance” described there, then it should work.

DISPLAY

I’m content to leave support for X11 based applications for a later iteration.

Opening files

I’m tempted to say “not a problem”. Any application that can be passed a filename should cope with the filename being invalid or the file being inaccessible. But if we don’t pass filenames in the first iteration we can postpone further consideration of this.

A first iteration

With the limitations discussed above, it seems much could be achieved by adding an OpenDesktop method to io.snapcraft.Launcher that accepts the name of the .desktop file, extracts and sanitizes the Exec line and execs the resulting command in much the same manner as OpenURL execs xdg-open.

Do you see anything I am missing?