A guide to creating graphical snaps for Ubuntu IoT devices. Learn how to build a digital signage app for kiosks, advertising screens and other embedded displays.

However the implementation we recommend in that tutorial has a flaw that I think need to be rectified. I want to go into the problem here, and share what I think is a better - but not perfect - solution.

The Wayland socket

Communication between a Wayland client (GUI app) and Wayland server (e.g. mir-kiosk) happens through a “socket” - a special file on the filesystem. By convention, this file is called “wayland-0” (that number can change) and is located in $XDG_RUNTIME_DIR.

In the desktop/Snap Classic world, $XDG_RUNTIME_DIR is a single directory shared between all applications, so both server and client can access the socket.

Not so simple in the Ubuntu Core world…

Sharing the Wayland socket between snaps

In Ubuntu Core, confined snaps each have their own $XDG_RUNTIME_DIR - to prevent leaking data between different snaps. But that makes sharing the Wayland socket problematic.

So we need mir-kiosk to provide the Wayland socket at a location that an application GUI snap can access and connect to it.

Snapd doesn’t provide any convenience to automatically put the socket in the application snap, so we need to engineer it ourselves.

Using the Content Interface

The content interface seemed to be the ideal solution to this - it allows one to share a directory from one snap with another. This is the approach I started with, and it did succeed.

My initial approach was this: mir-kiosk snap provides a “wayland-socket-dir” content interface slot, which essentially shared its $XDG_RUNTIME_DIR with any other snap that plugs into it. Clients could then point $XDG_RUNTIME_DIR environment variable to the shared directory and Wayland would work!

However with the benefit of hindsight, this approach has problems:

We just want to share a socket, not an entire directory.

Sockets require full read-write access, and content interface only sets permissions on the directory, meaning the directory needed full read-write permissions. This opens up a data leaking channel between 2 GUI snaps!

Client snaps overriding $XDG_RUNTIME_DIR made it especially easy for accidental data leaking to happen, as it is a commonly used default storage location for many libraries.

The existing “wayland” interface

But wait, isn’t there an existing wayland interface in snapd? Yes, it was formed for graphical snaps to run on Ubuntu Classic with Wayland. It has its own approach to sharing the Wayland socket which I find clunky, but also works:

The convention here is to place the Wayland socket in /run/user/$UID/. Outside the snap world, this is exactly where $XDG_RUNTIME_DIR points to. But inside a snap, $XDG_RUNTIME_DIR is a randomly generated subdirectory of the form: /run/user/$UID/XXXXXX - and AppArmor rules are used to confine snaps inside this directory.

The wayland interface has an exception to allow a snap to access /run/user/$UID/wayland-0 - and nothing else in that directory. So it is secure.

But that puts the responsibility on the application snap to check if that file exists, and link it into their own $XDG_RUNTIME_DIR.