跳转到内容

Bubblewrap

来自 Arch Linux 中文维基

Bubblewrap 是一款轻量化的沙箱应用,常为 Flatpak 和其他容器工具所用。安装和运行 bubblewrap 所需的资源非常少。虽然软件包名称是 bubblewrap,实际的命令行接口却是 bwrap(1)。Bubblewrap 所值得注意的特性包括支持 cgroup、IPC(进程间通信)、mount、network、PID、user、UTS namespacesseccomp 过滤。注意 bubblewrap 在沙箱内会丢弃所有的 capabilities,因此子任务的权限不能超过其父任务。但 bubblewrap 对文件路径的黑白名单缺乏明确支持。

警告:Bubblewrap 是一种能提供 namespaces 和 seccomp 过滤等沙箱化技术的工具。默认情况下,不提供能够隔离所用技术的缺陷的完整沙箱环境。运行不受信任的代码永远是危险的,沙箱化技术也不会改变这一事实。

安装

[编辑 | 编辑源代码]

安装 bubblewrapbubblewrap-gitAUR

注意:

配置

[编辑 | 编辑源代码]

可通过直接在命令行中调用或是作为组成复杂包装器的一部分 shell 脚本中使用 bubblewrap。与一些自动在沙箱内将 /var/etc 设置为只读的应用程序(例如 Firejail)不同,bubblewrap 不会做这样的操作假设。应该由用户根据想要沙箱化运行的程序来决定需要传入何种配置选项。以 setuid 权限运行的 bubblewrap 不会自动创建用户命名空间(user namespaces),但可以接受典型的环境变量,如 $HOME$USER

强烈建议安装 strace 软件包用于了解要以沙箱运行的程序的所需文件。

bubblewrap 配置管理器

[编辑 | 编辑源代码]

除了手动配置,也可以使用配置管理器并通过更简单的操作来自动化配置 bubblewrap。

  • Bubblejail — 基于 bubblewrap 的沙箱,有基于资源的权限模型(提供了用于权限配置的图形界面)。
https://github.com/igo95862/bubblejail || bubblejailAUR
  • portableAUR:简单易用的沙箱化框架,包括 D-Bus 代理过滤、数据隔离、访问控制以及其他功能。

使用示例

[编辑 | 编辑源代码]

参阅 Bubblewrap 示例以了解如何使用 bubblewrap。 除此以外,许多项目已证实 bubblewrap 可用于通常应用程序:

无操作调用(No-op invocation)bubblewrap 的示例如下:

$ bwrap --dev-bind / / bash

上述命令会创建一个大多数情况下与沙箱外部表现完全一致的 Bash 进程。如果沙箱化的程序出现异常行为,可以通过上述的无操作调用启动,然后逐步调整至更安全的配置。

注意:如果执行对象的拥有者(owner)和用户组(group)与执行者不一致,这个操作会把所有的拥有者(owner)和用户组(group)更改为 nobody,因此运行某些程序如 sudo,将不能正常工作。

创建一个简单的 Bash 沙箱:

  • 确定可用的内核命名空间(kernel namespaces):
$ ls /proc/self/ns
cgroup  ipc  mnt  net  pid  user uts
注意:user 的存在意味着内核已经通过 CONFIG_USER_NS=y 暴露出对用户命名空间(user namespaces)的支持。
  • 将宿主的整个 / 目录以只读模式绑定到沙箱内的 /
  • 创建一个新的用户命名空间(user namespace)并将用户标识符设为 256用户组标识符设为 512
$ 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

隔离文件系统

[编辑 | 编辑源代码]
警告:Bubblewrap 用户需自行负责定期更新文件系统树。

要进一步隐藏文件系统的内容(例如 /var/usr/bin/usr/lib 中的文件),甚至是用沙箱保护软件的安装,pacman 可以将软件包安装到隔离的文件系统中。

为能让 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 的配置文件:

  • 移除任何不需要的自定义仓库以及仅被宿主系统需要的 IgnorePkgIgnoreGroupNoUpgradeNoExtract 设置。
  • 可能需要移除 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

[编辑 | 编辑源代码]

绑定挂载宿主的 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

沙箱化 X11

[编辑 | 编辑源代码]

虽然 bwrap 为沙箱化的应用程序提供了一些非常不错的隔离功能,但对于应用程序来说,只要能访问 X11 socket,就仍然有能够逃离沙箱隔离的方法。

X11 下的应用程序之间没有互相隔离,这会让恶意软件能够监听输入、注入按键或记录其他应用程序的图像。

一种应对方式是换用 Wayland 混成器,该混成器不能从沙箱中访问 X 服务。Wayland 实现了不允许应用程序交互的特性。

而如果要继续使用 X11,应该使用 xpraxephyr。这些工具能够创建一个次要且仅用于运行被沙箱化的应用程序的 X11 实例,该实例会在用户目前使用的环境中的一个窗口中显示。以这种方式运行的应用程序窗口无法与其自身 X11 实例以外的环境交互。上述方式同样可与 bwrap 共同使用。

这篇文章的某些内容需要扩充。

原因:Bubblewrap 示例中的所有示例都仅仅只是 bind-mount 了 X11 socket。需要一些做了隔离的示例。 (在 Talk:Bubblewrap 中讨论)

要测试 X11 是否被隔离,运行 xinput test id(使用 xinput list 查找所需的 id)。 在没有额外隔离的情况下运行 X11 时,上述命令会显示任何能访问 X11 且够抓取键盘输入的其他应用程序,这种情况下恶意软件将能够记录按键。

使用 portals

[编辑 | 编辑源代码]

本文或本章节可能需要合并到XDG Desktop Portal

附注: 有独立页面。(在 Talk:Bubblewrap 中讨论)
警告:这其实是利用一些方法“欺骗”了 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

从被隔离的(wrapped)应用中打开 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 \
  ...

对于不使用 XDG 惯例的应用程序而言,绑定 /usr/bin/chromium 是必需的,比如 Mozilla Thunderbird。

New session

[编辑 | 编辑源代码]

一个关于 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 的示例代码。

没有声音输出

[编辑 | 编辑源代码]

本文或本章节的语言、语法或风格需要改进。参考:帮助:风格

原因:“特定程序”是什么程序? See Help:Style#Language register.(在Talk:Bubblewrap讨论)

对于使用 ALSA 声音系统的特定程序,添加如下选项:

--dev-bind /dev/snd /dev/snd

即可获得声音输出。

另请参见

[编辑 | 编辑源代码]