bubblewrap

提供: ArchWiki
2019年3月1日 (金) 00:47時点におけるKusakata (トーク | 投稿記録)による版 (カテゴリ変更)
ナビゲーションに移動 検索に移動

関連記事

bubblewrapFlatpak から発展した軽量な setuid サンドボックスアプリケーションです。インストール容量が小さくリソース要件は最小限です。アプリケーションパッケージ自体は bubblewrap と呼ばれますが、実際の実行バイナリや man ページで使われている名前は bwrap(1) です。bubblewrap は将来的に Tor Browser (Linux 版) の サンドボックス機構 として使われることが期待されています。特徴として cgroup/IPC/マウント/ネットワーク/PID/ユーザー/UTS 名前空間seccomp フィルタリングをサポートしています。bubblewrap はサンドボックス内の全てのケイパビリティを破棄して子タスクが親以上の権限を得られないようにします。ファイルパスベースのブラックリストやホワイトリストは対応していません。

警告: ユーザーやログインセッションの分離とは異なり、bubblewrap はカーネルのセキュリティ脆弱性の他にウィンドウコンポジタの脆弱性の影響を受けます。信頼できないコードを bubblewrap を実行しないようにユーザーは注意する必要があります。

インストール

bubblewrap または bubblewrap-gitAURインストールしてください。

ノート: Arch Linux カーネルにおける user_namespaces(7) のサポートに関する情報はセキュリティ#アプリケーションのサンドボックス化を見てください。

設定

bubblewrap はコマンドラインから直接起動したり、複雑なラッパー に含まれる シェルスクリプト で呼び出すことができます。サンドボックス内の /var/etc を自動的に読み取り専用に設定する Firejail などのアプリケーションと違って、bubblewrap はそのような操作を行いません。サンドボックス化したいアプリケーションにあわせてどのような設定オプションを指定するかはユーザー次第です。setuid 特権で実行された場合でも bubblewrap は自動的にユーザー名前空間を作成しないので $HOME$USER などの環境変数を利用することが可能です。

使用例

No-op

以下のように何もせずに bubblewrap を呼び出すことができます:

$ bwrap --dev-bind / / bash

サンドボックスの外のように振る舞う bash プロセスが生成されます。サンドボックス化したプログラムがおかしくなってしまう場合、上記の no-op から段々と設定をセキュアにしていくことができます。

Bash

シンプルな Bash のサンドボックスを作成:

  • 利用可能なカーネル名前空間を確認:
$ ls /proc/self/ns 
cgroup  ipc  mnt  net  pid  user uts
ノート: user が存在する場合、CONFIG_USER_NS=y によってカーネルのユーザー名前空間のサポートが有効になっています。
  • ホストの / ディレクトリ全体を読み取り専用としてサンドボックスの / にバインド。
  • 新しいユーザー名前空間を作成してユーザー ID256 に、グループ ID512 に設定。
$ bwrap --ro-bind / / --unshare-user --uid 256 --gid 512 bash
bash-4.4$ id
uid=256 gid=512 groups=512,65534(nobody)
bash-4.4$ ls -l /usr/bin/bash
-rwxr-xr-x 1 nobody nobody 811752 2017-01-01 04:20 /usr/bin/bash

dhcpcd

シンプルな dhcpcd のサンドボックスを作成:

  • 利用可能なカーネル名前空間を確認:
$ ls /proc/self/ns 
cgroup  ipc  mnt  net  pid  uts
ノート: user が存在しない場合、CONFIG_USER_NS=n でカーネルのユーザー名前空間が無効になっているか使用が制限されています。
  • ホストの / ディレクトリ全体を読み書き可能でサンドボックスの / にバインド。
  • 新しい 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
ヒント: unbound.service などの systemd ユニットファイルを bubblewrap する方法はsystemd#ユニットファイルの編集を見てください。

デスクトップ

デスクトップエントリで 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;
ノート: /dev/pty に書き込むには --dev /dev が必要です。
  • mupdf.sh シェルラッパーを組み込んだ MuPDF のデスクトップエントリの例:
[Desktop Entry]
Name=MuPDF
Exec=mupdf.sh %f
Icon=application-pdf.svg
Type=Application
MimeType=application/pdf;application/x-pdf;
ノート: mupdf.sh は PATH が通った場所に配置してください。例: PATH=$PATH:$HOME/bwrap

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 "$@")
ヒント: 既存の実行ファイルを /usr/bin/sh に置き換えてシェルラッパーを実行することでサンドボックスの中身やファイルシステムのデバッグや確認ができます。
$ 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 ディレクトリとそのサブディレクトリの中でしか実行されなくなります。
  • アプリケーションとプロセスのために新しい 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 "$@")
ノート: サンドボックスのファイルシステムを横断・確認するには実行パスに /usr/bin/sh/usr/bin/ls が必要です。
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

ファイルシステムの分離

警告: bubblewrap のユーザーはファイルシステムツリーを定期的に更新しなければなりません。

(/var, /usr/bin, /usr/lib の中身など) ファイルシステムの中身を遮蔽しながらソフトウェアのインストールをサンドボックス化したい場合、pacman で Arch のパッケージを分離したファイルシステムツリーにインストールすることができます。

pacman を使ってソフトウェアをファイルシステムツリーにインストールするには、fakerootfakechroot のインストールが必要です。

例として pacman で xterm パッケージを隔離ファイルシステムツリーにインストールしたいとすると、ツリーを以下のように準備します:

$ 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

~/sandboxes/${MYPACKAGE}/files/etc/pacman.conf を編集して使用する pacman の設定を調整すると良いでしょう:

  • 不必要なカスタムリポジトリやホスト環境でしか必要ない IgnorePkg, IgnoreGroup, NoUpgrade, NoExtract の設定を削除。
  • CheckSpace オプションを削除して pacman がディスク容量をチェックするために root ファイルシステムを検索するときのエラーを消す。

base グループと必須の fakeroot を分離ファイルシステムツリーにインストール:

$ fakechroot fakeroot pacman -Syu \
    --root ~/sandboxes/${MYPACKAGE}/files \
    --dbpath ~/sandboxes/${MYPACKAGE}/files/var/lib/pacman \
    --config ~/sandboxes/${MYPACKAGE}/files/etc/pacman.conf \
    base fakeroot

同じオプションを使って bubblewrap を何度も呼び出すことになるので、以下のようにエイリアスを作成:

$ alias bw-install='bwrap                        \
     --bind ~/sandboxes/${MYPACKAGE}/files/ /    \
     --ro-bind /etc/resolv.conf /etc/resolv.conf \
     --tmpfs /tmp                                \
     --proc /proc                                \
     --dev /dev                                  \
     --chdir /                                   '

ロケールを設定してください:

$ nano -w ~/sandboxes/${MYPACKAGE}/files/etc/locale.gen
$ bw-install locale-gen

pacman のキーリングを設定:

$ bw-install fakeroot pacman-key --init
$ bw-install fakeroot pacman-key --populate archlinux

以下のように xterm パッケージをインストール:

$ bw-install fakeroot pacman -S ${MYPACKAGE}

pacman コマンドが失敗する場合、キーリングを生成するコマンドをもう一度実行してみてください。

これで xterm を含む分離ファイルシステムツリーが作られました。bw-install を使ってファイルシステムツリーをアップグレードすることができます。

bubblewrap でソフトウェアを実行することができます (上記の例では commandxterm になります):

$ bwrap                                          \
     --ro-bind ~/sandboxes/${MYPACKAGE}/files/ / \
     --ro-bind /etc/resolv.conf /etc/resolv.conf \
     --tmpfs /tmp                                \
     --proc /proc                                \
     --dev /dev                                  \
     --chdir /                                   \
     command

一部のファイルをパッケージ間で共有することもできます。既存のファイルシステムツリーのファイルのハードリンクを作成して新しいツリーで再利用することが可能です:

$ cp -al ~/sandboxes/${MYPARENTPACKAGE} ~/sandboxes/${MYPACKAGE}

bw-install fakechroot fakeroot pacman … から pacman を呼び出して通常通りにインストールを行ってください。

トラブルシューティング

X11 を使う

ホストの X11 ソケットを別の X11 ソケットにバインドマウントしても上手く行かないことがあります:

--bind /tmp/.X11-unix/X0 /tmp/.X11-unix/X8 --setenv DISPLAY :8

ホストの X11 ソケットをサンドボックス内の同じソケットにバインドマウントすることで解決します:

--bind /tmp/.X11-unix/X0 /tmp/.X11-unix/X0 --setenv DISPLAY :0

X11 のサンドボックス化

bwrap はアプリケーションをサンドボックス化するための素晴らしい隔離機能を備えていますが、X11 ソケットにアクセスできてしまえば簡単に離脱することができます。X11 にはアプリケーション間の分離が存在しないためセキュリティ的に危険です。サンドボックスから X サーバーにアクセスできないようにする方法として Wayland コンポジタに切り替える方法があります。

また、xpraxephyr を使って新しい X11 環境で実行させるという方法もあります。この方法で bwrap を使うこともできます。

X11 の隔離化をテストするには、xinput test <id> を実行してください (<id> は xinput list で確認できるキーボード ID に置き換えてください)。X11 が分離化されていない場合、X11 にアクセスできるアプリケーションはキーロガーのように他のアプリケーションのキーボード入力を盗聴することができてしまいます。

ラッピングしたアプリケーションから URL を開く

ラッピングした IRC やメールクライアントで URL を開くと、起動するブラウザプロセスも同じサンドボックス内で動作します。アプリケーションの分離が強固な場合、うまく機能しないことがあります。Firejail では ラッピングしたアプリケーションにブラウザと同じ権限を与える ことで解決しますが、パーミッションがゆるくなってしまいます。

開いた URL をサンドボックスの外と通信するほうが良手です。以下のように snapd-xdg-open を使ってください:

  1. snapd-xdg-open-gitAUR をインストール
  2. bwrap コマンドラインで以下を追加:
$ bwrap ... \
  --ro-bind /run/user/$UID/bus /run/user/$UID/bus \
  --ro-bind /usr/lib/snapd-xdg-open/xdg-open /usr/bin/xdg-open \
  --ro-bind /usr/lib/snapd-xdg-open/xdg-open /usr/bin/chromium \
  ...

/usr/bin/chromium のバインドは Mozilla Thunderbird など XDG に準拠していないプログラムでのみ必要です。

新規セッション

TIOCSTI にはサンドボックスから脱出できるセキュリティ問題が存在します (CVE-2017-5226)。この問題に対応するために、bubblewrap には setsid() を呼び出す新しいオプション '--new-session' が追加されています。ただしこのオプションはときとして扱いにくい挙動上の問題を起こすことがあります。例えば bwrap コマンドでシェルのジョブ制御が機能しなくなります。

可能であればオプションを使用することが推奨されていますが、そうでない場合は別の方法で問題を解決することが推奨されます。例えば flatpak は SECCOMP を使用します: https://github.com/flatpak/flatpak/commit/902fb713990a8f968ea4350c7c2a27ff46f1a6c4

参照