Bubblewrap

Bubblewrap is an
unprivileged sandboxing tool. Kernel features it also has:
User/IPC/PID/Network/UTS/cgroup
namespaces and
Seccomp filters.
How bubblewrap works, as stated in the
README.md:
:bubblewrap works by creating a new, completely empty, mount namespace where the root is on a tmpfs that is invisible from the host, and will be automatically cleaned up when the last process exits. You can then use commandline options to construct the root filesystem and process environment and command to run in the namespace.
== Installation ==
Install :
== How to workout what a program needs ==
=== Prerequisites ===
First make sure to have a user editable directory in .
This page will use , create it if it does
not exist:
Add it to :
Will need to relog for this to apply.
=== Basic bwrap setup ===
Lets assume you want to sandbox and are using Wayland
only. Here is how you might go about that.
Create inside and make it
executable:
Use to determine the file type of :
Since it is just a shell script, we can use to view it:
Since we are assuming Wayland only we can just skip to
. Run on it:
It is an
Executable and Linkable Format (ELF)
file. So we know we need the ELF interpreter
. We also know we need
, since it has to know where the command
is located.
As the argument to , put
, this will pass only the first argument and if
there is none, will default to , the current directory. We
will also need ,
since we are not passing the whole filesystem. This will get the
absolute pathname using , so you can pass a relative
argument and still bind the argument:
 --ro-bind "${1:-./}" "$(realpath "${1:-./}")" \
 /usr/libexec/imv-wayland "${1:-./}"
Find necessary shared libraries, except ones loaded at runtime:
It outputs a lot of things but we only need a few; the directory path of
the majority and the 4 paths that start with
. Filter the output to see those clearer:
In total:
 --ro-bind /lib/ld-musl-x86_64.so.1 /lib/ld-musl-x86_64.so.1 \
 --ro-bind /lib/libblkid.so.1 /lib/libblkid.so.1 \
 --ro-bind /lib/libmount.so.1 /lib/libmount.so.1 \
 --ro-bind /lib/libz.so.1 /lib/libz.so.1 \
 --ro-bind /usr/lib/ /usr/lib/ \
Since this is a shell script, lets use a helpful command:
 set -u
if the shell tries to expand an unset parameter, it will error (with a
few exceptions).
Since this is for a GUI Wayland program, so lets also add some prerequisites:
 --setenv XDG_RUNTIME_DIR "$XDG_RUNTIME_DIR" \
for determining the directory for the wayland socket;
 --setenv WAYLAND_DISPLAY "$WAYLAND_DISPLAY" \
for determining the socket;
 --ro-bind "${XDG_RUNTIME_DIR}/${WAYLAND_DISPLAY}" "${XDG_RUNTIME_DIR}/${WAYLAND_DISPLAY}" \
mount readonly.
Lets also add some nice to haves:
 --unshare-all \
will create a new user/ipc/pid/net/utc namespaces and try to create a
new cgroup namespace if possible;
 --new-session
will create a new terminal session for the sandbox, disconnecting from
the controlling terminal so for example it can't inject input into the
terminal;
 --die-with-parent
will ensure child process ( in this case) dies when
 parent dies.
We might also have a file:
 --ro-bind-try "${XDG_CONFIG_HOME}/imv/config" "${XDG_CONFIG_HOME}/imv/config" \
this will add your local config to if you have one and if not
will still continue.
Pass to sandbox:
 --setenv XDG_CONFIG_HOME "$XDG_CONFIG_HOME" \
but this isn't always defined, so lets fallback to the
XDG Base Directory
default:
 XDG_CONFIG_HOME="${XDG_CONFIG_HOME:-$HOME/.config}"
this will use if it's set, otherwise
fallback to the default of .
 --ro-bind /bin/sh /bin/sh \
Needed to use and have various information in the window
title.
 now looks like:
Now lets run , go into a directory with an image:
Add:
 --ro-bind /usr/share/X11/xkb/ /usr/share/X11/xkb/ \
to . XKB
is a keyboard keymap support library.
After adding the above, run it again:
Add:
 --dev-bind /dev/dri/renderD128 /dev/dri/renderD128 \
and run again:
 --ro-bind /sys/dev/char/ /sys/dev/char/ \
Access to character devices.
 --ro-bind /sys/devices/pci0000:00/ /sys/devices/pci0000:00/ \
Access to PCI resources.
 --clearenv \
Finally we can unset all environment variables, except for
 and any we set with .
Now should show images and your file should
work (if you have one). If you do not use commands, the finished
 should look like:
If you do use commands however, you will notice it is only showing
substitute characters.
If you try to use a command it will say:
 Fontconfig error: Cannot load default config file: No such file: (null)
Look at the manpage (which is from
) we see that is the system
font configuration directory and
 is the per-user configuration
directory. is added with
 so it doesn't have to exist:
 --ro-bind /etc/fonts/ /etc/fonts/ \
 --ro-bind-try "${XDG_CONFIG_HOME}/fontconfig/" "${XDG_CONFIG_HOME}/fontconfig/" \
The default directories scanned for font files are
 and .
 added with :
 --ro-bind /usr/share/fonts/ /usr/share/fonts/ \
 --ro-bind-try "${XDG_DATA_HOME}/fonts/" "${XDG_DATA_HOME}/fonts/" \
Pass to sandbox:
 --setenv XDG_DATA_HOME "$XDG_DATA_HOME" \
just like for , this isn't always defined, so
fallback to
XDG Base Directory
default:
 XDG_DATA_HOME="${XDG_DATA_HOME:-$HOME/.local/share}"
use if set, else use .
The user cache of font information is also needed, by default
:
 --bind-try "${XDG_CACHE_HOME}/fontconfig/" "${XDG_CACHE_HOME}/fontconfig/" \
Pass to sandbox:
 --setenv XDG_CACHE_HOME "$XDG_CACHE_HOME" \
just like for , this isn't always defined, so
fallback to
XDG Base Directory
default:
 XDG_CACHE_HOME="${XDG_CACHE_HOME:-$HOME/.cache}"
use if set, else use .
 --ro-bind /usr/share/icu/ /usr/share/icu/ \
Is also needed or when you do it will terminate the
process. ICU provides Unicode and Globalization support.
The updated should look like this:
==== See what exists in the sandbox ====
Finally test what all is allowed by replacing
 with and
adding . Check around and see what the
filesystem is like:
Invoke :
Show what environment variables are active:
See what directories are at root:
 when done:
Do not forget to change it back:
All done with a basic wrapper.
=== Seccomp ===
== .desktop integration ==
XDG Desktop Entry Specification
are a set of standards describing how a particular program is to be
launched, how it appears in menus, etc.
The default .desktop file for is at
. Move it to
.
Only 3 options will need to be changed: Name/Name[en_US], what shows up
in the application menu in a graphical file manager (if you have one
installed); Exec, program to execute:
The program (from the package) can be
used to open files based on the MIME
type + corresponding entry in
 and
.
Install if it is not installed already, it
comes with two commands that are needed and
:
=== Validate ===
It is a good idea to validate using
:
=== Update database ===
This will make entries in take
precedence over system-wide files ().
However has precedence over
both.
Updating the database, will create
:
== Troubleshooting ==
=== Can't find what path is missing ===
If all else fails start broad and work toward narrowing. See if
 works with the program at all:
If that works start to narrow:
Keep going till you have narrowed as much as possible.
== See also ==
* Bubblewrap/Examples
* ArchWiki: Bubblewrap
** ArchWiki: Bubblewrap/Examples
* ArchWiki: Desktop entries (*.desktop files)
Category:Desktop
Category:Security