Runing Sandboxed GUI Apps In Podman

Hi, I have recently switched to OpenSUSE Aeon and am loving the experience so far. For development, I simply install my whole toolchain and my editor inside a “distrobox” and everything just works™ including Wayland integration and even hardware graphics acceleration!

However, something that concerns me about this development setup with distrobox is that it offers no sandboxing or isolation. Furthermore, it seems the project is very clear about not offering sandboxing and not wanting to offer it either (as per [Feature] Sandboxed mode · Issue #28 · 89luca89/distrobox · GitHub).

My main concern is that if I were to fall victim to a “supply chain attack” or similar, any rogue process would have full access to my entire home directory and everything stored in there. So at the very least I want my development environment not to have access to my real home directory. Additional sandboxing would of course also be nice to the extent that is possible without breaking things like graphics.

I thought that simply using Podman directly could be an alternative to get what I want but unfortunately I have not been able to get that working (even after many attempts…). The main problem is that I am not managing to get Wayland (and likely GPU access) working inside the container for GUI apps.

For testing I am using the following simple Dockerfile:

FROM registry.opensuse.org/opensuse/tumbleweed:latest

RUN zypper refresh && \
    zypper install -y sudo Mesa-demo-x && \
    useradd -m user && \
    echo 'user ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers

USER user

And the following command to launch Podman:

podman run -it \
  --rm \
  --userns=keep-id \
  --group-add keep-groups \
  -e XDG_RUNTIME_DIR=$XDG_RUNTIME_DIR \
  -e WAYLAND_DISPLAY=$WAYLAND_DISPLAY \
  -v $XDG_RUNTIME_DIR/$WAYLAND_DISPLAY:$XDG_RUNTIME_DIR/$WAYLAND_DISPLAY \
  -v /dev/dri:/dev/dri \
  --network host \
  tumble-sudo

I then try to run glxinfo in the container but always get hit with Error: unable to open display.

Most of the parameters I am passing have been driven by a suspicion that there might be permission errors but I am not sure about that and nothing I have tried so far makes any difference. I even tried setting SELinux to “permissive” mode under a suspicion that it might the problem, but no dice.

I am not sure if this is an Aeon specific issue or if I am just doing something wrong in general, but any help would be greatly appreciated!

GLX is by definition OpenGL implementation for X11. You do not pass any X11 information, so it fails to open X11 display. Have you tried any native Wayland client?

@arvidjaar thanks, I completely missed the fact that glxinfo only uses X11! Thus I have now switched to using weston for testing instead. Beyond using wayland, it also provided plenty of additional debug info.

I finally managed to get things running now with:

FROM registry.opensuse.org/opensuse/tumbleweed:latest

RUN zypper refresh && \
    zypper install -y sudo weston && \
    useradd -m user && \
    echo 'user ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers

USER user

and

podman run -it --rm \
  --userns=keep-id \
  --device /dev/dri \
  --network host \
  --security-opt=label=disable \
  -e WAYLAND_DISPLAY=$WAYLAND_DISPLAY \
  -e XDG_RUNTIME_DIR=/tmp \
  -v $XDG_RUNTIME_DIR/$WAYLAND_DISPLAY:/tmp/$WAYLAND_DISPLAY \
  -v /dev/dri:/dev/dri \
  tumble-sudo

Now when I run weston, I see it’s window pop up and I get the following output on the console:

Date: 2025-07-06 UTC
[12:53:06.639] weston 14.0.2
               https://wayland.freedesktop.org
               Bug reports to: https://gitlab.freedesktop.org/wayland/weston/issues/
               Build: 14.0.2
[12:53:06.639] Command line: weston
[12:53:06.639] OS: Linux, 6.15.4-1-default, #1 SMP PREEMPT_DYNAMIC Mon Jun 30 10:37:39 UTC 2025 (55e70a8), x86_64
[12:53:06.639] Flight recorder: enabled
[12:53:06.639] warning: XDG_RUNTIME_DIR "/tmp" is not configured
correctly.  Unix access mode must be 0700 (current mode is 0777),
and must be owned by the user UID 1000 (current owner is UID 0).
Refer to your distribution on how to get it, or
http://www.freedesktop.org/wiki/Specifications/basedir-spec
on how to implement it.
[12:53:06.639] Starting with no config file.
[12:53:06.639] Output repaint window is 7 ms maximum.
[12:53:06.639] Loading module '/usr/lib64/libweston-14/wayland-backend.so'
[12:53:06.640] Loading module '/usr/lib64/libweston-14/gl-renderer.so'
amdgpu: os_same_file_description couldn't determine if two DRM fds reference the same file description.
If they do, bad things may happen!
[12:53:06.653] Using rendering device: /dev/dri/renderD128
[12:53:06.656] EGL version: 1.5
[12:53:06.656] EGL vendor: Mesa Project
[12:53:06.656] EGL client APIs: OpenGL OpenGL_ES 
[12:53:06.656] EGL features:
               EGL Wayland extension: yes
               context priority: yes
               buffer age: yes
               partial update: no
               swap buffers with damage: yes
               configless context: yes
               surfaceless context: yes
               dmabuf support: modifiers
amdgpu: amdgpu_cs_ctx_create2 failed. (-13)
[12:53:06.657] GL version: OpenGL ES 3.2 Mesa 25.1.4
[12:53:06.657] GLSL version: OpenGL ES GLSL ES 3.20
[12:53:06.657] GL vendor: AMD
[12:53:06.657] GL renderer: AMD Radeon Graphics (radeonsi, gfx1200, LLVM 20.1.7, DRM 3.63, 6.15.4-1-default)
[12:53:06.659] GL ES 3.2 - renderer features:
               read-back format: ARGB8888
               glReadPixels supports y-flip: yes
               glReadPixels supports PBO: yes
               wl_shm 10 bpc formats: yes
               wl_shm 16 bpc formats: yes
               wl_shm half-float formats: yes
               internal R and RG formats: yes
               OES_EGL_image_external: yes
[12:53:06.659] Using GL renderer
...

Since it mentions my AMD GPU for OpenGL, I assume it is managing to get access to the GPU as well. However, when I try running the “Zed” editor which only supports Vulkan, it complains that it is using the LLVMPipe backend so it seems Vulkan is not able to get access to my GPU for some reason. Since I want Vulkan support, I do still need to figure this part out.

I briefly tried getting X11 working inside the container too but ran into problems with X11 permissions. I quickly gave up on that though as I don’t currently need support for it.

A key thing thing I realised is that the --userns=keep-id flag is required to have access to the wayland socket. I also realised that it is better to mount $XDG_RUNTIME_DIR under /tmp inside the container. This is because weston tries to create lockfiles inside this directory and does not have write access to /run/user/1000 by default (I guess this could also just be fixed in the Dockerfile though).

Beyond fixing Vulkan, there are a few other things I want to fix with this setup to have more serious security:

  • Use a proper SELinux policy for the container instead of just disabling it. Hopefully udica should make that simple enough though.
  • Prompt the user to choose a password for sudo inside the container rather than just using “NOPASSWD”. Even though the container does not run as root, the “fake” root user inside the container can only do limited damage, but it is probably still better to protect it.
  • Based on the discussion at GitHub - containers/bubblewrap: Low-level unprivileged sandboxing tool used by Flatpak and similar projects, it could be useful to add “seccomp filters” here if possible (I have no idea )

Ah okay, it seems the Vulkan issue is related to missing “ICD” files for my GPU (under /usr/share/vulkan/icd.d). As per Vulkan - openSUSE Wiki, it was possible to fix this by installing libvulkan_radeon for my AMD GPU. Presumably libvulkan_intelworks for Intel GPUs and I have no idea what is needed for Nvidia.

Another thing I found doesn’t work is opening URLs in a browser from apps in the container. I guess this is to be expected. Any idea what mechanism usually makes this work (and thus which “holes to poke” in the sandbox)?

I am not sure I understand what you are trying to do. You tagged this topic with aeon and gnome which implies you already have Wayland compositor in the GUI session. What are you trying to achieve with invoking yet another Wayland compositor?

The standard way is to use org.freedesktop.portal.OpenURI xdg-dektop-portal API which is what xdg-open tool is using when flatpak is detected as “desktop environment”.

I am not sure I understand what you are trying to do. You tagged this topic with aeon and gnome which implies you already have Wayland compositor in the GUI session. What are you trying to achieve with invoking yet another Wayland compositor?

Ah sorry for the confusion. I just picked weston as a random thing to run for testing that is easy to install and can be a wayland client. It is not part of the solution in any way. Instead I will host my editor and custom compiled code directly inside the host GNOME compositor.

The standard way is to use org.freedesktop.portal.OpenURI xdg-dektop-portal API which is what xdg-open tool is using when flatpak is detected as “desktop environment”.

Thanks!