Can't get snap gui apps (notepadqq and firefox) to run in LXD/LXC container

I’ve set up an LXD/LXC container in Ubuntu and can’t get GUI SNAPs to run in the container (which is also Ubuntu), I believe there is an issue accessing the display. X11 “deb” apps work fine after tweaking a few settings as described in the very helpful article https://blog.simos.info/how-to-run-graphics-accelerated-gui-apps-in-lxd-containers-on-your-ubuntu-desktop/, but SNAPs do not.

When starting notepadqq or firefox I get ln errors such as:
ln: failed to create symbolic link ‘/home/ubuntu/snap/notepadqq/841/snap/notepadqq/841/Documents’: No such file or directory
ln: failed to create symbolic link ‘/home/ubuntu/snap/notepadqq/841/snap/notepadqq/841/Desktop’: No such file or directory
ln: failed to create symbolic link ‘/home/ubuntu/snap/notepadqq/841/snap/notepadqq/841/Downloads’: No such file or directory
ln: failed to create symbolic link ‘/home/ubuntu/snap/notepadqq/841/snap/notepadqq/841/Music’: No such file or directory
ln: failed to create symbolic link ‘/home/ubuntu/snap/notepadqq/841/snap/notepadqq/841/Pictures’: No such file or directory
ln: failed to create symbolic link ‘/home/ubuntu/snap/notepadqq/841/snap/notepadqq/841/Videos’: No such file or directory
ln: failed to create symbolic link ‘/home/ubuntu/snap/notepadqq/841/snap/notepadqq/841/Templates’: No such file or directory

Then the gui window does not display and the app eventually gets this error:
QXcbConnection: Could not connect to display :0
Aborted (core dumped)

x11 apps (such as firefox) work fine if installed with apt.

The host is running Ubuntu 18.04 and so is the container.

dmesg shows this error for notepadqq:

[349363.925230] audit: type=1107 audit(1527123518.868:1456): pid=516 uid=103 auid=4294967295 ses=4294967295 msg='apparmor=“DENIED” operation=“dbus_signal” bus=“system” path="/org/freedesktop/NetworkManager/ActiveConnection/7" interface=“org.freedesktop.NetworkManager.Connection.Active” member=“PropertiesChanged” name=":1.10" mask=“receive” pid=25488 label=“snap.notepadqq.notepadqq” peer_pid=545 peer_label=“unconfined”

An X11 application tries to find a Unix socket of a X11 server in order to open it and display there.
The blog post instructions set up a location for that socket, and that location can be easily be found by Deb-packaged applications.

With snap packages it needs a bit more searching as to where the apps are looking for that Unix socket, and adapt the configuration so that they can easily find it.

I believe the snaps exclusively use the X11 abstract unix socket which the usual X11 bind-mount will not provide.

@monstermunchkin is currently working on extending our proxy device in LXD to support proxying unix-sockets, including abstract unix sockets, which should take care of this (though some aspects of the X11 protocol make this slightly tricky).

Thanks. Any idea why the symbolic links aren’t working?

To add a bit more on this:

  1. If you run a GUI application on the host,

    $ strace -ffe trace=connect xclock
    connect(3, {sa_family=AF_LOCAL, sun_path=@"/tmp/.X11-unix/X0"}, 20) = 0
    connect(4, {sa_family=AF_LOCAL, sun_path=@"/tmp/.ICE-unix/14229"}, 23) = 0
    ^C

You can see that the application manages to successfully (= 0) open the abstract (@) Unix socket called /tmp/.X11-unix/X0 and show up its window on your desktop.

  1. If you then run a GUI application in a LXD container (a la guiapps),

    $ strace -ffe trace=connect xclock
    connect(3, {sa_family=AF_UNIX, sun_path=@"/tmp/.X11-unix/X0"}, 20) = -1 ECONNREFUSED (Connection refused)
    connect(3, {sa_family=AF_UNIX, sun_path="/tmp/.X11-unix/X0"}, 110) = 0
    ^C

You can see that the application tried unsuccessfully (= -1) to open the abstract (@) Unix socket called /tmp/.X11-unix/X0, and got a Connection Refused (ECONNREFUSED).

But then, the application attempts and manages to successfully (= 0) open the normal Unix socket called /tmp/.X11-unix/X0 and show up its window on your desktop.

  1. If you now try the same with a snap in a LXD container (I use the snap xbill-xaw as there is no xclock snap), you get

    $ snap run --strace="-ffe trace=connect" xbill-xaw

    connect(3, {sa_family=AF_UNIX, sun_path=@"/tmp/.X11-unix/X0"}, 20) = -1 ECONNREFUSED (Connection refused)
    connect(3, {sa_family=AF_UNIX, sun_path="/tmp/.X11-unix/X0"}, 110) = -1 ENOENT (No such file or directory)

    Error: Can’t open display: :0

You can see that the application tried unsuccessfully (= -1) to open the abstract (@) Unix socket called /tmp/.X11-unix/X0, and got a Connection Refused (ECONNREFUSED).

But then, the application attempts unsuccessfully (= -1) to open a normal Unix socket called /tmp/.X11-unix/X0 and gets the error that there is no such file (ENOENT).

The reason why the snap cannot see the container’s /tmp/.X11-unix/X0 is that the snap cannot touch the system-wide /tmp. It is part of the confinement of the snaps. A snap gets a dynamic /tmp, and it looks like

$ sudo ls -al /tmp/snap.1000_xbill-xaw_O2878c/tmp/
total 1
drwxrwxrwt 2 ubuntu ubuntu 2 May 28 18:13 .
drwx------ 3 root   ubuntu 3 May 28 18:13 ..

Therefore, it could be possible to get all these to work but it would be very ugly because the path for /tmp has a random component (O2878c in this case, and changes on each reboot).
In addition, the core of the problem is that snapd (the service of snaps) tries to limit the sharing of files via /tmp for obvious security issues. See discussion on this at https://forum.snapcraft.io/t/sharing-files-via-tmp/1613/1

The snapd services only shares the abstract (with @ but not the one without the @) Unix socket with the snap package per

So what can happen? As @stgraber says, if LXD can share the abstract Unix socket of the host to the container, then snapd can use that socket and the GUI snaps should work in LXD containers as well.

3 Likes

Thanks, great explanation!

Amazing explanation! Thank you so much for that.

Does anyone know if this is already resolved / if there is any workaround? @stgraber?

I even tried updating my snap to have X11 , desktop, unity and more plugs… but that didn’t help.
I’m now trying make a link between the /tmp/.X11 to the /snap/…

The issue with snaps is that if they have the strict confinement, then they cannot read the container’s /tmp or the containers ${HOME} dot files (like ~/.Xauthority).

In that respect, you should be able to get, for example, the Skype snap to work (has classic confinement), but for other snaps it might work or not. Specifically, if the snap has the [home] plug then it can read the ${HOME} (but still no dot files, nor the /tmp/) so it could read ${HOME}/Xauthority. In addition, you could put the X11 socket file into each snap’s ${HOME}/snap/mysnap/common/ directory and then figure out how to get the snap to look into there.

There is a patch and discussion at https://github.com/lxc/lxd/issues/4718 on this.

Ideally, the result should be something that will make everything work fine and nice.