Bubblewrap
Bubblewrap 是一款輕量化的沙箱應用,常為 Flatpak 和其他容器工具所用。安裝和運行 bubblewrap 所需的資源非常少。雖然軟體包名稱是 bubblewrap,實際的命令行接口卻是 bwrap(1)。Bubblewrap 所值得注意的特性包括支持 cgroup、IPC(進程間通信)、mount、network、PID、user、UTS namespaces 和 seccomp 過濾。注意 bubblewrap 在沙箱內會丟棄所有的 capabilities,因此子任務的權限不能超過其父任務。但 bubblewrap 對文件路徑的黑白名單缺乏明確支持。
安裝 bubblewrap包 或 bubblewrap-gitAUR。
- 有關 Arch Linux 內核所支持的 user_namespaces(7) 的更多信息,參見安全#沙盒程序。
- linux-hardened包 用戶請忽略上述兩個軟體包並請考慮安裝 bubblewrap-suid包。更多相關信息請參閱 FS#63316。
可通過直接在命令行中調用或是作為組成複雜包裝器的一部分 shell 腳本中使用 bubblewrap。與一些自動在沙箱內將 /var 和 /etc 設置為只讀的應用程式(例如 Firejail)不同,bubblewrap 不會做這樣的操作假設。應該由用戶根據想要沙箱化運行的程序來決定需要傳入何種配置選項。以 setuid 權限運行的 bubblewrap 不會自動創建用戶命名空間(user namespaces),但可以接受典型的環境變量,如 $HOME 和 $USER。
強烈建議安裝 strace包 軟體包用於了解要以沙箱運行的程序的所需文件。
除了手動配置,也可以使用配置管理器並通過更簡單的操作來自動化配置 bubblewrap。
- Bubblejail — 基於 bubblewrap 的沙箱,有基於資源的權限模型(提供了用於權限配置的圖形界面)。
- portableAUR:簡單易用的沙箱化框架,包括 D-Bus 代理過濾、數據隔離、訪問控制以及其他功能。
參閱 Bubblewrap 示例以了解如何使用 bubblewrap。 除此以外,許多項目已證實 bubblewrap 可用於通常應用程式:
無操作調用(No-op invocation)bubblewrap 的示例如下:
$ bwrap --dev-bind / / bash
上述命令會創建一個大多數情況下與沙箱外部表現完全一致的 Bash 進程。如果沙箱化的程序出現異常行為,可以通過上述的無操作調用啟動,然後逐步調整至更安全的配置。
nobody,因此運行某些程序如 sudo,將不能正常工作。創建一個簡單的 Bash 沙箱:
- 確定可用的內核命名空間(kernel namespaces):
$ ls /proc/self/ns
cgroup ipc mnt net pid user uts
user 的存在意味著內核已經通過 CONFIG_USER_NS=y 暴露出對用戶命名空間(user namespaces)的支持。$ 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
在桌面項中使用 bubblewrap:
- 將宿主的整個
/目錄以讀寫模式綁定到沙箱內的/。 - 將沙箱內的
/var和/etc目錄重新以只讀模式綁定。 - 掛載一個新的 devtmpfs 文件系統到沙箱內的
/dev。 - 在沙箱化的
/run目錄中創建一個 tmpfs 文件系統。 - 創建一個新的網絡命名空間(network namespace)以禁用網絡訪問。
[Desktop Entry] Name=nano Editor Exec=bwrap --bind / / --ro-bind /var /var --ro-bind /etc /etc --dev /dev --tmpfs /run --unshare-net st -e nano -o . %f Type=Application MimeType=text/plain;
/dev/pty,--dev /dev是必需的。- MuPDF 的桌面項示例(配合一個
mupdf.sh的 shell 包裝器):
[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
要進一步隱藏文件系統的內容(例如 /var、/usr/bin 和 /usr/lib 中的文件),甚至是用沙箱保護軟體的安裝,pacman 可以將軟體包安裝到隔離的文件系統中。
為能讓 pacman 將軟體安裝到文件系統樹中,需要先安裝 fakeroot包 和 fakechroot包。
假設用戶想用 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 就不會在檢查磁碟空間的時候抱怨找不到根文件系統。
然後將 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):
$ alias bw-install='bwrap \
--bind ~/sandboxes/${MYPACKAGE}/files/ / \
--ro-bind /etc/resolv.conf /etc/resolv.conf \
--tmpfs /tmp \
--proc /proc \
--dev /dev \
--chdir / '
編輯 ~/sandboxes/${MYPACKAGE}/files/etc/locale.gen 並運行下面的命令以設置 locale:
$ bw-install locale-gen
然後設置 pacman 的 keyring:
$ bw-install fakeroot pacman-key --init $ bw-install fakeroot pacman-key --populate
現在就可以安裝所需的 xterm 軟體包了:
$ bw-install fakeroot pacman -S ${MYPACKAGE}
如果 pacman 在這一步執行失敗,嘗試再次運行用於 populate keyring 的命令。
成功後,用戶現在擁有一個包含 xterm 的隔離的文件系統樹。之後可以再次使用 bw-install(上面的例子中配置好的別名)來更新文件系統樹。
接下來就可以使用 bubblewrap 來運行軟體了。本例中的 command 應該替換成 xterm。
$ 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 socket 到另一個 X11 socket 可能無法工作:
--bind /tmp/.X11-unix/X0 /tmp/.X11-unix/X8 --setenv DISPLAY :8
一種解決方法是將宿主的 X11 socket 綁定掛載到沙箱中的同一個 socket:
--bind /tmp/.X11-unix/X0 /tmp/.X11-unix/X0 --setenv DISPLAY :0
雖然 bwrap 為沙箱化的應用程式提供了一些非常不錯的隔離功能,但對於應用程式來說,只要能訪問 X11 socket,就仍然有能夠逃離沙箱隔離的方法。
X11 下的應用程式之間沒有互相隔離,這會讓惡意軟體能夠監聽輸入、注入按鍵或記錄其他應用程式的圖像。
一種應對方式是換用 Wayland 混成器,該混成器不能從沙箱中訪問 X 服務。Wayland 實現了不允許應用程式交互的特性。
而如果要繼續使用 X11,應該使用 xpra 或 xephyr。這些工具能夠創建一個次要且僅用於運行被沙箱化的應用程式的 X11 實例,該實例會在用戶目前使用的環境中的一個窗口中顯示。以這種方式運行的應用程式窗口無法與其自身 X11 實例以外的環境交互。上述方式同樣可與 bwrap 共同使用。
要測試 X11 是否被隔離,運行 xinput test id(使用 xinput list 查找所需的 id)。
在沒有額外隔離的情況下運行 X11 時,上述命令會顯示任何能訪問 X11 且夠抓取鍵盤輸入的其他應用程式,這種情況下惡意軟體將能夠記錄按鍵。
xdg-desktop-portal,讓它認為被沙箱化的程序是一個 Flatpak 程序。再次提醒,運行不受信任的代碼永遠是危險的,就算是通過 Portals 在沙箱中運行也是。通過一些解決方法,或許可以利用 XDG Desktop Portals 來沙箱化一些應用程式。
這麼做的優點是,使用文件系統 portals,能夠在不給予應用程式對於家目錄(home directory)的訪問權限的情況下,讓應用程式依然可以訪問文件。
然而出於安全原因,使用 portals 需要欺騙 xdg-desktop-portal,讓它認為被沙箱化的程序是 Flatpak 的一部分。這可以通過在沙箱的根文件系統中添加一個 .flatpak-info 文件來實現。
此外,用戶還應該運行 xdg-dbus-proxy 以更好地顆粒化控制 portals 的訪問權限。此命令應該在沙箱環境下運行,因此也需要一個 .flatpak-info 文件。但 proxy 至少需要能夠有 org.freedesktop.portal.Flatpak 的 talk 訪問權限。更多 portals 請訪問 Flatpak 文檔。
常見的案例是允許一個被完全限制 home 目錄訪問權限的程序僅僅能夠訪問用戶在文件選擇器中選擇的文件和目錄。用以下參數啟動 xdg-dbus-proxy 可以實現這個目的:
--talk=org.freedesktop.portal.Documents --talk=org.freedesktop.portal.Flatpak --talk=org.freedesktop.portal.Desktop --talk=org.freedesktop.portal.FileChooser
完整示例如下:
APP_NAME=app.application.Name
APP_FOLDER="$XDG_RUNTIME_DIR/app/$APP_NAME"
mkdir -p "$APP_FOLDER"
set_up_dbus_proxy() {
bwrap \
--new-session \
--symlink /usr/lib64 /lib64 \
--ro-bind /usr/lib /usr/lib \
--ro-bind /usr/lib64 /usr/lib64 \
--ro-bind /usr/bin /usr/bin \
--bind "$XDG_RUNTIME_DIR" "$XDG_RUNTIME_DIR" \
--ro-bind-data 3 "/.flatpak-info" \
--die-with-parent \
-- \
env -i xdg-dbus-proxy \
"$DBUS_SESSION_BUS_ADDRESS" \
"$APP_FOLDER/bus" \
--filter \
--log \
--talk=org.freedesktop.portal.Flatpak \
--call="org.freedesktop.portal.Desktop=org.freedesktop.portal.Settings.Read@/org/freedesktop/portal/desktop" \
--broadcast="org.freedesktop.portal.Desktop=org.freedesktop.portal.Settings.SettingChanged@/org/freedesktop/portal/desktop" 3<<EOF
[Application]
name=$APP_NAME
EOF
}
set_up_dbus_proxy &
sleep 0.1
bwrap \
...
--ro-bind-data 3 /.flatpak-info \
...
3<<EOF
[Application]
name=$APP_NAME
EOF
當被隔離的 IRC 或電子郵件客戶端嘗試打開一個 URL,通常會嘗試啟動一個瀏覽器進程,而被啟動的瀏覽器進程會與被隔離的應用程式一樣運行在同一個沙箱中,而一個被良好隔離的應用程式很有可能沒法正常工作。Firejail 所用的處理方式是給予被隔離的應用程式所有瀏覽器也擁有的權限,然而這也意味著分配大量的權限。
對於這個問題,更好的解決方法是將打開 URL 的請求發送到沙箱外。參照下列示例使用 snapd-xdg-open:
- 安裝 snapd-xdg-open-gitAUR
- 在
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 \ ...
對於不使用 XDG 慣例的應用程式而言,綁定 /usr/bin/chromium 是必需的,比如 Mozilla Thunderbird。
一個關於 TIOCSTI 的安全問題(CVE-2017-5226)會引起沙箱逃逸。 為防止這個問題,bubblewrap 已引入一個新選項「--new-session」,該選項會調用 setsid()。 然而,這個選項在一些情況下會引起行為問題(behavioural issues)從而難以使用。 例如,這個選項會讓 shell 的作業控制(job control)無法應用於 bwrap 命令。
如果應用程式開發人員有其他方式解決上述漏洞(CVE-2017-5226),可以不用這個選項(比如 Flatpak 所處理的用於 SECCOMP 的方式),但除此以外建議儘量使用「--new-session」選項。
特定應用程式如 Chromium 已經使用 suid 幫助文件實現了其自身的沙箱環境。這個機制會在以 bubblewrap 容器中運行這些軟體時被阻止。
一種解決方法是讓應用程式使用 bubblewrap 創建的命名空間。比如可以使用 zypakAUR,同時它也是 Flatpak 所使用的方式,用於在額外的命名空間中運行基於 electron 的應用程式。這個連結中有關於如何使用 zypak 運行 Chromium 或 Electron 的示例代碼。
對於使用 ALSA 聲音系統的特定程序,添加如下選項:
--dev-bind /dev/snd /dev/snd
即可獲得聲音輸出。