Bubblewrap/例
目次
dhcpcd
シンプルな dhcpcd のサンドボックスを作成:
- 利用可能なカーネル名前空間を確認:
$ ls /proc/self/ns cgroup ipc mnt net pid uts
- ホストの
/
ディレクトリ全体を読み書き可能でサンドボックスの/
にバインド。 - 新しい devtmpfs ファイルシステムをサンドボックスの
/dev
にマウント。 - 新しい IPC 名前空間とコントロールグループ名前空間を作成。
- 新しい UTS 名前空間を作成して
dhcpcd
をホストネームとして設定。
# /usr/bin/bwrap --bind / / --dev /dev --unshare-ipc --unshare-cgroup --unshare-uts --hostname dhcpcd /usr/bin/dhcpcd -q -b
Unbound
粒度の細かい複雑な Unbound のサンドボックスを作成:
- システムの
/usr
ディレクトリを読み取り専用でサンドボックスの/usr
にバインド。 - システムの
/usr/lib
ディレクトリからサンドボックスの/lib64
に対してシンボリックリンクを作成。 - システムの
/etc
ディレクトリを読み取り専用でサンドボックスの/etc
にバインド。 - サンドボックスの中に空の
/var
と/run
ディレクトリを作成。 - 新しい devtmpfs ファイルシステムをサンドボックスの
/dev
にマウント。 - 新しい IPC 名前空間と PID 名前空間とコントロールグループ名前空間を作成。
- 新しい UTS 名前空間を作成して
unbound
をホストネームとして設定。
# /usr/bin/bwrap --ro-bind /usr /usr --symlink usr/lib /lib64 --ro-bind /etc /etc --dir /var --dir /run --dev /dev --unshare-ipc --unshare-pid --unshare-cgroup --unshare-uts --hostname unbound /usr/bin/unbound -d
Desktop
デスクトップエントリで bubblewrap を活用:
- ホストの
/
ディレクトリ全体を読み書き可能でサンドボックスの/
にバインド。 - サンドボックスの
/var
と/etc
ディレクトリを読み取り専用で再バインド - 新しい devtmpfs ファイルシステムをサンドボックスの
/dev
にマウント。 - サンドボックスの
/run
ディレクトリに tmpfs ファイルシステムを作成。 - 新しいネットワーク名前空間を作成してネットワークアクセスを無効化。
[Desktop Entry] Name=nano Editor Exec=bwrap --bind / / --dev /dev --tmpfs /run --unshare-net st -e nano -o . %f Type=Application MimeType=text/plain;
mupdf.sh
シェルラッパーを組み込んだ MuPDF のデスクトップエントリの例:
[Desktop Entry] Name=MuPDF Exec=mupdf.sh %f Icon=application-pdf.svg Type=Application MimeType=application/pdf;application/x-pdf;
MuPDF
bwrap の能力と柔軟性が一番良くわかるのはシェルラッパーの中に環境を作成するときです:
- ホストの
/usr/bin
ディレクトリを読み取り専用でサンドボックスの/usr/bin
にバインド。 - ホストの
/usr/lib
ディレクトリを読み取り専用でサンドボックスの/usr/lib
にバインド。 - システムの
/usr/lib
ディレクトリからサンドボックスの/lib64
に対してシンボリックリンクを作成。 - サンドボックスの
/usr/lib/gcc
の上に tmpfs ファイルシステムを作成。- 上記の設定でサンドボックスから
/usr/lib/gcc
の中身を効率的に遮蔽できます。
- 上記の設定でサンドボックスから
- 新しい tmpfs ファイルシステムをサンドボックスの
$HOME
ディレクトリとして作成。 .Xauthority
ファイルと Documents ディレクトリをサンドボックスに読み取り専用としてバインド。- 上記の設定で
.Xauthority
ファイルと Documents ディレクトリが再帰的にホワイトリストに追加されます。
- 上記の設定で
- 新しい tmpfs ファイルシステムをサンドボックスの
/tmp
ディレクトリとして作成。 - X11 ソケットをサンドボックスに読み取り専用としてバインドしてホワイトリストに追加。
- 実行中のカーネルによってサポートされている全ての名前空間に対してプレイベートなコンテナを複製・作成。
- カーネルが非特権のユーザー名前空間をサポートしてなかった場合、作成がスキップされます。
- ネットワークコンポーネントをプライベート名前空間に配置しない。
- 上記の設定で URI ハイパーリンクを辿ってネットワークにアクセスできます。
#!/bin/sh #~/bwrap/mupdf.sh (exec bwrap \ --ro-bind /usr/bin /usr/bin \ --ro-bind /usr/lib /usr/lib \ --symlink usr/lib /lib64 \ --tmpfs /usr/lib/gcc \ --tmpfs $HOME \ --ro-bind $HOME/.Xauthority $HOME/.Xauthority \ --ro-bind $HOME/Documents $HOME/Documents \ --tmpfs /tmp \ --ro-bind /tmp/.X11-unix/X0 /tmp/.X11-unix/X0 \ --unshare-all \ --share-net \ /usr/bin/mupdf "$@")
$ bwrap \ --ro-bind /usr/bin /usr/bin \ --ro-bind /usr/lib /usr/lib \ --symlink usr/lib /lib64 \ --tmpfs /usr/lib/gcc \ --tmpfs $HOME \ --ro-bind $HOME/.Xauthority $HOME/.Xauthority \ --ro-bind $HOME/Desktop $HOME/Desktop \ --tmpfs /tmp \ --ro-bind /tmp/.X11-unix/X0 /tmp/.X11-unix/X0 \ --unshare-all \ --share-net \ /usr/bin/sh bash-4.4$ ls -AF .Xauthority Documents/
bubblewrap によるファイルシステムを作成するときに一番重要なルールは実行されるコマンドの順番です。上記の MuPDF の例の場合:
- tmpfs ファイルシステムを作成してから
.Xauthority
ファイルと Documents ディレクトリをバインドマウントした場合:
--tmpfs $HOME \ --ro-bind $HOME/.Xauthority $HOME/.Xauthority \ --ro-bind $HOME/Documents $HOME/Documents \
bash-4.4$ ls -a . .. .Xauthority Documents
.Xauthority
をバインドマウントしてから tmpfs ファイルシステムを作成して上書きするとサンドボックスからは Documents ディレクトリだけが見えます:
--ro-bind $HOME/.Xauthority $HOME/.Xauthority \ --tmpfs $HOME \ --ro-bind $HOME/Documents $HOME/Documents \
bash-4.4$ ls -a . .. Documents
p7zip
既知の脆弱性 に対してパッチが適用されていないアプリケーションは特に bubblewrap を使用する価値があります:
- ホストの
/usr/bin/7za
実行パスを読み取り専用でサンドボックスにバインド。 - システムの
/usr/lib
ディレクトリからサンドボックスの/lib64
に対してシンボリックリンクを作成。 - tmpfs オーバーレイでサンドボックス化した
/usr/lib/modules
と/usr/lib/systemd
の中身をブラックリストに追加。 - 新しい devtmpfs ファイルシステムをサンドボックスの
/dev
にマウント。 - ホストの
/sandbox
ディレクトリを読み書き可能でサンドボックスの/sandbox
ディレクトリにバインド。- シェルラッパーから呼び出すことで 7za はホストの
/sandbox
ディレクトリとそのサブディレクトリの中でしか実行されなくなります。
- シェルラッパーから呼び出すことで 7za はホストの
- アプリケーションとプロセスのために新しい cgroup/IPC/ネットワーク/PID/UTS 名前空間を作成。
- カーネルが非特権のユーザー名前空間をサポートしていなかった場合、作成はスキップされます。
- 新しいネットワーク名前空間を作成することでサンドボックスからネットワークにアクセスできなくなります。
p7zip
というホストネームをサンドボックスに追加。XAUTHORITY
環境変数の設定を解除して X11 の接続クッキーの場所を遮蔽。- 7za を動作させるのに X11 ディスプレイサーバーに接続する必要はありません。
- 新しいターミナルセッションを起動してキーボードの入力がサンドボックス外に流出することを防止。
#!/bin/sh #~/bwrap/pz7ip.sh (exec bwrap \ --ro-bind /usr/bin/7za /usr/bin/7za \ --symlink usr/lib /lib64 \ --tmpfs /usr/lib/modules \ --tmpfs /usr/lib/systemd \ --dev /dev \ --bind /sandbox /sandbox \ --unshare-all \ --hostname p7zip \ --unsetenv XAUTHORITY \ --new-session \ /usr/bin/7za "$@")
bwrap \ --ro-bind /usr/bin/7za /usr/bin/7za \ --ro-bind /usr/bin/ls /usr/bin/ls \ --ro-bind /usr/bin/sh /usr/bin/sh \ --symlink usr/lib /lib64 \ --tmpfs /usr/lib/modules \ --tmpfs /usr/lib/systemd \ --dev /dev \ --bind /sandbox /sandbox \ --unshare-all \ --hostname p7zip \ --unsetenv XAUTHORITY \ --new-session \ /usr/bin/sh bash: no job control in this shell bash-4.4$ ls -AF dev/ lib64@ usr/ bash-4.4$ ls -l /usr/lib/modules total 0 bash-4.4$ ls -l /usr/lib/systemd total 0 bash-4.4$ ls -AF /dev console full null ptmx@ pts/ random shm/ stderr@ stdin@ stdout@ tty urandom zero bash-4.4$ ls -A /usr/bin 7za ls sh
Firefox
Network facing applications with large surface attack areas are also ideal candidates to be bubblewrapped:
- Transmission included in the sandbox to launch with magnet and torrent links
- Example wrap supports audio (PulseAudio) and printing (CUPS/Avahi) under GNOME (Wayland)
- Paths in
~/.config/transmission/settings.json
should reflect the--setenv HOME
variable
- Paths in
- Full paths are used to allow for keyboard bindings in environments which do not support variable expansion.
- WebRenderer and hardware (accelerated) compositing support included
bwrap \ --symlink usr/lib /lib \ --symlink usr/lib64 /lib64 \ --symlink usr/bin /bin \ --symlink usr/bin /sbin \ --ro-bind /usr/lib /usr/lib \ --ro-bind /usr/lib64 /usr/lib64 \ --ro-bind /usr/bin /usr/bin \ --ro-bind /usr/lib/firefox /usr/lib/firefox \ --ro-bind /usr/share/applications /usr/share/applications \ --ro-bind /usr/share/gtk-3.0 /usr/share/gtk-3.0 \ --ro-bind /usr/share/fontconfig /usr/share/fontconfig \ --ro-bind /usr/share/icu /usr/share/icu \ --ro-bind /usr/share/drirc.d /usr/share/drirc.d \ --ro-bind /usr/share/fonts /usr/share/fonts \ --ro-bind /usr/share/glib-2.0 /usr/share/glib-2.0 \ --ro-bind /usr/share/glvnd /usr/share/glvnd \ --ro-bind /usr/share/icons /usr/share/icons \ --ro-bind /usr/share/libdrm /usr/share/libdrm \ --ro-bind /usr/share/mime /usr/share/mime \ --ro-bind /usr/share/X11/xkb /usr/share/X11/xkb \ --ro-bind /usr/share/icons /usr/share/icons \ --ro-bind /usr/share/mime /usr/share/mime \ --ro-bind /etc/fonts /etc/fonts \ --ro-bind /etc/resolv.conf /etc/resolv.conf \ --ro-bind /usr/share/ca-certificates /usr/share/ca-certificates \ --ro-bind /etc/ssl /etc/ssl \ --ro-bind /etc/ca-certificates /etc/ca-certificates \ --dir /run/user/"$(id -u)" \ --ro-bind /run/user/"$(id -u)"/pulse /run/user/"$(id -u)"/pulse \ --ro-bind /run/user/"$(id -u)"/wayland-1 /run/user/"$(id -u)"/wayland-1 \ --dev /dev \ --dev-bind /dev/dri /dev/dri \ --ro-bind /sys/dev/char /sys/dev/char \ --ro-bind /sys/devices/pci0000:00 /sys/devices/pci0000:00 \ --proc /proc \ --tmpfs /tmp \ --bind /home/example/.mozilla /home/example/.mozilla \ --bind /home/example/.config/transmission /home/example/.config/transmission \ --bind /home/example/Downloads /home/example/Downloads \ --setenv HOME /home/example \ --setenv GTK_THEME Adwaita:dark \ --setenv MOZ_ENABLE_WAYLAND 1 \ --setenv PATH /usr/bin \ --hostname RESTRICTED \ --unshare-all \ --share-net \ --die-with-parent \ --new-session \ /usr/bin/firefox
Enhancing privacy
- Further restrictions can be made by removing specific entries
- Remove the following entry to remove audio support:
--ro-bind /run/user/"$(id -u)"/pulse /run/user/"$(id -u)"/pulse \
/sandbox
represents an arbitrary location defined by the user to hold desired profile information- This allows for the use of a sanitized profile copied into
/sandbox
via a script/cron job or manually e.g.
- This allows for the use of a sanitized profile copied into
$ cp -pR ~/.mozilla /sandbox/
The location can be a network share, a USB mount, or a local filesystem or ramfs/tmpfs location
- Set
/home/r
to obscure the actual/home/example
- Set new user ID and group ID values
bwrap \ .... --bind /sandbox/.mozilla /home/r/.mozilla \ --bind /sandbox/Downloads /home/r/Downloads \ ... --setenv HOME /home/r \ ... --uid 200 --gid 400 \ ... /usr/bin/firefox --no-remote --private-window
Chromium
A simple chromium sandbox on wayland and with pipewire:
bwrap \ --symlink usr/lib /lib \ --symlink usr/lib64 /lib64 \ --symlink usr/bin /bin \ --symlink usr/bin /sbin \ --ro-bind /usr/lib /usr/lib \ --ro-bind /usr/lib64 /usr/lib64 \ --ro-bind /usr/bin /usr/bin \ --ro-bind /etc /etc \ --ro-bind /usr/lib/chromium /usr/lib/chromium \ --ro-bind /usr/share /usr/share \ --dev /dev \ --dev-bind /dev/dri /dev/dri \ --proc /proc \ --ro-bind /sys/dev/char /sys/dev/char \ --ro-bind /sys/devices /sys/devices \ --ro-bind /run/dbus /run/dbus \ --dir "$XDG_RUNTIME_DIR" \ --ro-bind "$XDG_RUNTIME_DIR/wayland-1" "$XDG_RUNTIME_DIR/wayland-1" \ --ro-bind "$XDG_RUNTIME_DIR/pipewire-0" "$XDG_RUNTIME_DIR/pipewire-0" \ --ro-bind "$XDG_RUNTIME_DIR/pulse" "$XDG_RUNTIME_DIR/pulse" \ --tmpfs /tmp \ --dir $HOME/.cache \ --bind $HOME/.config/chromium $HOME/.config/chromium \ --bind $HOME/Downloads $HOME/Downloads \ /usr/bin/chromium --enable-features=UseOzonePlatform --ozone-platform=wayland
- PipeWire:
--ro-bind "/run/user/$(id -u)/pipewire-0" "/run/user/$(id -u)/pipewire-0" \
- If you are not using pipewire, feel free to remove this line
--bind $HOME/.config/chromium $HOME/.config/chromium \
mounts your chromium configuration directory in the sandbox as readable and writable--bind $HOME/Downloads $HOME/Downloads \
mounts your ~/Downloads directory in the sandbox as readable and writable- This example can be further improved for more isolation.
Skype for Linux
skypeforlinux-stable-binAUR should be started with /usr/share/skypeforlinux/skypeforlinux
instead of /usr/bin/skypeforlinux
, because the latter is just a wrapper script which forks the main process in the background and terminates, which conflicts with the --die-with-parent
bwrap option.
The following example provides these features:
env -i
ensures that all environment variables are unset.- Network is shared with the host (
--share-net
),/etc/resolv.conf
is bind-mounted. - Xorg access: bind the
/tmp/.X11-unix/X0
socket, set$DISPLAY
. - D-Bus: bind the
/run/user/$UID/bus
socket, set$DBUS_SESSION_BUS_ADDRESS
. - Audio: bind the PulseAudio socket.
- Video: dev-bind the
/dev/video0
device.
The directory on the host where you want to keep the Skype profile can be configured with $HOST_PROFILE_PATH
.
env -i bwrap \ --ro-bind /usr /usr \ --dir /home/r \ --dir /tmp \ --dir /var \ --dir /run/user/$UID \ --proc /proc \ --dev /dev \ --symlink usr/lib /lib \ --symlink usr/lib64 /lib64 \ --symlink usr/bin /bin \ --symlink usr/sbin /sbin \ --symlink ../tmp /var/tmp \ --bind "$HOST_PROFILE_PATH" /home/r/.config/skypeforlinux \ --ro-bind /etc/resolv.conf /etc/resolv.conf \ --ro-bind /tmp/.X11-unix/X0 /tmp/.X11-unix/X0 \ --ro-bind /run/user/$UID/bus /run/user/$UID/bus \ --ro-bind /run/user/$UID/pulse /run/user/$UID/pulse \ --dev-bind /dev/video0 /dev/video0 \ --chdir / \ --unshare-all \ --share-net \ --hostname RESTRICTED \ --die-with-parent \ --new-session \ --setenv PATH /usr/bin \ --setenv HOME /home/r \ --setenv XDG_RUNTIME_DIR "/run/user/$UID" \ --setenv DISPLAY "$DISPLAY" \ --setenv DBUS_SESSION_BUS_ADDRESS "unix:path=/run/user/$UID/bus" \ /usr/share/skypeforlinux/skypeforlinux
Steam
A simple Steam sandbox
#!/usr/bin/bash set -e STEAM_HOME="$HOME/.local/share/steam_sandbox" RUN_USER="/run/user/$UID" mkdir -p "$STEAM_HOME" _bind() { _bind_arg=$1 shift for _path in "$@"; do args+=("$_bind_arg" "$_path" "$_path") done } bind() { _bind --bind-try "$@" } robind() { _bind --ro-bind-try "$@" } devbind() { _bind --dev-bind-try "$@" } args=( --tmpfs /tmp --proc /proc --dev /dev --dir /etc --dir /var --dir "$RUN_USER" --bind "$STEAM_HOME" "$HOME" --dir "$HOME" --dir "$XDG_CONFIG_HOME" --dir "$XDG_CACHE_HOME" --dir "$XDG_DATA_HOME" --dir "$XDG_STATE_HOME" --symlink /usr/lib /lib --symlink /usr/lib /lib64 --symlink /usr/bin /bin --symlink /usr/bin /sbin --symlink /run /var/run ) robind \ /usr \ /etc \ /opt \ /sys \ /var/empty \ /var/lib/alsa \ /var/lib/dbus \ "$RUN_USER/systemd/resolve" devbind \ /dev/dri \ /dev/nvidia* \ # steam bind \ "$HOME/.Xauthority" \ "$HOME/.local/bin/proton" \ "$HOME/.pki" \ "$HOME/.steam" \ "$HOME/.steampath" \ "$HOME/.steampid" \ "$HOME/Downloads" \ "$RUN_USER"/.mutter-X* \ "$RUN_USER"/ICE* \ "$RUN_USER"/dbus* \ "$RUN_USER"/gnome* \ "$RUN_USER"/pipewire* \ "$RUN_USER"/pulse* \ "$RUN_USER"/wayland* \ "$RUN_USER/at-spi" \ "$RUN_USER/bus" \ "$RUN_USER/dconf" \ "$RUN_USER/systemd" \ "$XDG_CACHE_HOME/mesa_shader_cache" \ "$XDG_CACHE_HOME/nv" \ "$XDG_CACHE_HOME/nvidia" \ "$XDG_CACHE_HOME/radv_builtin_shaders64" \ "$XDG_CONFIG_HOME/Epic" \ "$XDG_CONFIG_HOME/Loop_Hero" \ "$XDG_CONFIG_HOME/MangoHud" \ "$XDG_CONFIG_HOME/ModTheSpire" \ "$XDG_CONFIG_HOME/RogueLegacy" \ "$XDG_CONFIG_HOME/RogueLegacyStorageContainer" \ "$XDG_CONFIG_HOME/cef_user_data" \ "$XDG_CONFIG_HOME/proton" \ "$XDG_CONFIG_HOME/pulse" \ "$XDG_CONFIG_HOME/unity3d" \ "$XDG_DATA_HOME/3909/PapersPlease" \ "$XDG_DATA_HOME/Colossal Order" \ "$XDG_DATA_HOME/Dredmor" \ "$XDG_DATA_HOME/FasterThanLight" \ "$XDG_DATA_HOME/HotlineMiami" \ "$XDG_DATA_HOME/IntoTheBreach" \ "$XDG_DATA_HOME/Paradox Interactive" \ "$XDG_DATA_HOME/PillarsOfEternity" \ "$XDG_DATA_HOME/RogueLegacy" \ "$XDG_DATA_HOME/RogueLegacyStorageContainer" \ "$XDG_DATA_HOME/Steam" \ "$XDG_DATA_HOME/SuperHexagon" \ "$XDG_DATA_HOME/Terraria" \ "$XDG_DATA_HOME/applications" \ "$XDG_DATA_HOME/aspyr-media" \ "$XDG_DATA_HOME/bohemiainteractive" \ "$XDG_DATA_HOME/cdprojektred" \ "$XDG_DATA_HOME/feral-interactive" \ "$XDG_DATA_HOME/frictionalgames" \ "$XDG_DATA_HOME/icons" \ "$XDG_DATA_HOME/proton" \ "$XDG_DATA_HOME/vpltd" \ "$XDG_DATA_HOME/vulkan" \ "/var/lib/bluetooth" \ /run/systemd \ /tmp/.ICE-unix \ /tmp/.X11-unix exec bwrap "${args[@]}" /usr/lib/steam/steam "$@"
Filesystem isolation
To further hide the contents of the file system (such as those in /var
, /usr/bin
and /usr/lib
) and to sandbox even the installation of software, pacman can be made to install Arch packages into isolated filesystem trees.
In order to use pacman for installing software into the filesystem trees, you will need to install fakeroot and fakechroot.
Suppose you want to install the xterm
package with pacman into an isolated filesystem tree. You should prepare your tree like this:
$ MYPACKAGE=xterm $ mkdir -p ~/sandboxes/${MYPACKAGE}/files/var/lib/pacman $ mkdir -p ~/sandboxes/${MYPACKAGE}/files/etc $ cp /etc/pacman.conf ~/sandboxes/${MYPACKAGE}/files/etc/pacman.conf
You may want to edit ~/sandboxes/${MYPACKAGE}/files/etc/pacman.conf
and adjust the pacman configuration used:
- Remove any undesired custom repositories and
IgnorePkg
,IgnoreGroup
,NoUpgrade
andNoExtract
settings that are needed only for the host system. - You may need to remove the
CheckSpace
option so pacman will not complain about errors finding the root filesystem for checking disk space.
Then install the base
group along with the needed fakeroot into the isolated filesystem tree:
$ fakechroot fakeroot pacman -Syu \ --root ~/sandboxes/${MYPACKAGE}/files \ --dbpath ~/sandboxes/${MYPACKAGE}/files/var/lib/pacman \ --config ~/sandboxes/${MYPACKAGE}/files/etc/pacman.conf \ base fakeroot
Since you will be repeatedly calling bubblewrap with the same options, make an alias:
$ alias bw-install='bwrap \ --bind ~/sandboxes/${MYPACKAGE}/files/ / \ --ro-bind /etc/resolv.conf /etc/resolv.conf \ --tmpfs /tmp \ --proc /proc \ --dev /dev \ --chdir / '
You will need to set up the locales by editing ~/sandboxes/${MYPACKAGE}/files/etc/locale.gen
and running:
$ bw-install locale-gen
Then set up pacman’s keyring:
$ bw-install fakeroot pacman-key --init $ bw-install fakeroot pacman-key --populate
Now you can install the desired xterm
package.
$ bw-install fakeroot pacman -S ${MYPACKAGE}
If the pacman command fails here, try running the command for populating the keyring again.
Congratulations. You now have an isolated filesystem tree containing xterm
. You can use bw-install
again to upgrade your filesystem tree.
You can now run your software with bubblewrap. command
should be xterm
in this case.
$ bwrap \ --ro-bind ~/sandboxes/${MYPACKAGE}/files/ / \ --ro-bind /etc/resolv.conf /etc/resolv.conf \ --tmpfs /tmp \ --proc /proc \ --dev /dev \ --chdir / \ command
Note that some files can be shared between packages. You can hardlink to all files of an existing parent filesystem tree to reuse them in a new tree:
$ cp -al ~/sandboxes/${MYPARENTPACKAGE} ~/sandboxes/${MYPACKAGE}
Then proceed with the installation as usual by calling pacman from bw-install fakechroot fakeroot pacman ...
.