8
12
2021
10

使用 bwrap 沙盒

本文来自依云's Blog,转载请注明。

bwrap 是命令的名字。这个项目的名字叫 bubblewrap。它是一个使用 Linux 命名空间的非特权沙盒(有用户命名空间支持的话)。

我之前使用过 Gentoo 的 sandbox 工具。它是 Gentoo 用于打包的工具,使用的是 LD_PRELOAD 机制,所以并不可靠。主要用途也就是避免打包软件的时候不小心污染到用户家目录。

使用 bwrap 的话,限制是强制的,没那么容易绕过(至于像 Go 这种因为不使用 libc 而意外绕过就更难得了)。不过 bwrap 不会在触发限制的时候报错。

bwrap 的原理是,把 / 放到一个 tmpfs 上,然后需要允许访问的目录通过 bind mount 弄进来。所以没弄进来的部分就是不存在,写数据的话就存在内存里,用完就扔掉了。这一点和 systemd 也不一样——systemd 会把不允许的地方挂载一个没权限访问的目录过去。

bwrap 的挂载分为只读和可写挂载。默认是 nodev 的,所以在里边是不能挂载硬盘设备啥的。它也提供最简 /proc 和 /dev,需要手动指定。整个 / 都是通过命令行来一点点填充内容的,所以很容易漏掉部分内容(比如需要联网的时候忘记挂载 resolv.conf 或者 TLS 证书),而不会不小心允许不应当允许访问的地方(当然前提是不偷懒直接把外面的 / 挂载过去啦)。

至于别的命名空间,有 --unshare-all 选项,不用写一堆了。如果需要网络,就加个 --share-net(这个选项文档里没写)。没有别的网络方案,因为没特权,不能对网络接口进行各种操作。--die-with-parent 可以保证不会有残留进程一直跑着。

我目前的打包命令长这样:

alias makepkg='bwrap --unshare-all --share-net --die-with-parent \
  --ro-bind /usr /usr --ro-bind /etc /etc --proc /proc --dev /dev \
  --symlink usr/bin /bin --symlink usr/bin /sbin --symlink usr/lib /lib --symlink usr/lib /lib64 \
  --bind $PWD /build/${PWD:t} --ro-bind /var/lib/pacman /var/lib/pacman --ro-bind ~/.ccache ~/.ccache \
  --bind ~/.cache/ccache ~/.cache/ccache --chdir /build/${PWD:t} /usr/bin/makepkg'

以后应该随着问题的出现还会修改的。

其实我学 bwrap 主要不是自己打包啦(毕竟基本上都交给 lilac 了),而是给 lilac 加固。Arch 的打包脚本是 shell 脚本,所以很多时候不执行脚本就没办法获取一些信息、进行某些操作。唉,这些发行版都喜欢糙快猛的风格,然后在上边打各种补丁。deb 和 rpm 的打包也都是基于 shell 脚本的。而 lilac 经常通过脚本编辑打包脚本,或者从 AUR 取,万一出点事情,把不该删的东西给删掉了,或者把私钥给上传了,就不好了。所以前些天我给 lilac 执行 PKGBUILD 的地方全部加上了 bwrap。期间还发现 makepkg --printsrcinfo 不就是读取 PKGBUILD 然后打印点信息嘛,竟然不断要求读取 install 脚本,还要对打包目录可写……

另一个用法是,跑不那么干净的软件。有些软件不得不用,又害怕它在自己家里拉屎,就可以让它在沙盒里放肆了。比如使用反斜杠作为文件路径分隔符写一堆奇怪文件名的 WPS Office。再比如不确定软件会不会到处拉屎,所以事先确认一下。我以前使用的是基于 systemd-nspawn 和 overlayfs 的方案(改进自基于 aufs 和 lxc 的方案所以名字没改),不过显然 bwrap 更轻量一些。跑 GUI 的话,我用的命令长这样:

bwrap --unshare-all --die-with-parent --ro-bind / / \
  --tmpfs /sys --tmpfs /home --tmpfs /tmp --tmpfs /run --proc /proc --dev /dev \
  --ro-bind ~/.fonts ~/.fonts --ro-bind ~/.config/fontconfig ~/.config/fontconfig \
  --bind ~/.cache/fontconfig ~/.cache/fontconfig --ro-bind ~/.Xauthority ~/.Xauthority \
  --ro-bind /tmp/.X11-unix /tmp/.X11-unix --ro-bind /run/user/$UID/bus /run/user/$UID/bus \
  --chdir ~ /bin/bash

其实还可以用来给别的发行版编译东西,取代我之前使用 systemd-nspawn 的方案。bwrap 在命令行上指定如何挂载,倒是十分方便灵活,很适合这种需要共享工作目录的情况呢。以后有需要的时候我再试试看。(好像一般人都是使用 docker / podman 的,但是我喜欢使用自己建立和维护的 rootfs,便于开发和调试,也更安全。)

和 bwrap 类似的工具还有 SELinux 和 AppArmor。它们是作用于整个系统的,Arch Linux 安装会很麻烦,对于我的需求也过于复杂。Firejail 是面向应用程序的,但是配置起来也挺不容易。bwrap 更偏重于提供底层功能而不是完整的解决方案,具体用法可以让用户自由发挥。

Category: Linux | Tags: Arch Linux linux 安全 | Read Count: 52188
sbilly 说:
Aug 15, 2021 01:47:08 AM

基于 chroot 的?

Avatar_small
依云 说:
Aug 15, 2021 02:50:20 PM

基于 namespace 的。chroot 只是 bwrap 其中的一个步骤。

竹林里有冰 说:
Aug 17, 2021 01:38:28 AM

之前找了好久bwrap的使用教程都没找到,今天偶然间翻依云姐姐的博客居然翻到了,好诶

大漠落日 说:
Sep 07, 2021 01:37:15 PM

jail chroot 了解一下.

muwuren 说:
Nov 08, 2021 09:43:22 AM

嘿,我毕设就是这个思路写的,不过功能很少,挂载也很暴力,直接使用layer将根目录挂载到/tmp下,同时结合namespace和chroot限制进程。

Henry-ZHR 说:
Jan 22, 2022 08:22:06 PM

GUI 的能用输入法吗?我的 ibus + rime 似乎不太行

Avatar_small
依云 说:
Jan 22, 2022 10:19:21 PM

你把相关文件 bind mount 进去就可以用呗。XIM 只需要 X,GTK 和 Qt 都走的 D-Bus,因此需要把 /run/user/$UID 给 bind mount 了(然后环境变量 DBUS_SESSION_BUS_ADDRESS 别忘记,还是输入法自己用的环境变量也别忘记)。

Henry-ZHR 说:
Jan 22, 2022 11:27:10 PM

感觉可能是 ibus 的问题

https://github.com/ibus/ibus/blob/d9ff2bb6b04a7cf7d99f4e9832b4b8905858178c/src/ibusshare.c#L243-L244

如果那个进程不在的话就直接不干了 不知道为什么要这样设计

而且确实单单 bwrap --bind / / --unshare-pid 输入法就无法工作了

有空我自己再编译一个试试

Henry-ZHR 说:
Jan 22, 2022 11:30:40 PM

blame 了一下,看起来只是为了确认进程是否存活,删了应该也问题不大

以及有个 IBUS_ADDRESS 环境变量可以跳过这个流程,不过好像没什么比较文明的方法拿到 坏耶

Henry-ZHR 说:
Jan 24, 2022 08:55:04 AM

IBUS_ADDRESS 不行,自己编译打包也不行,但我找到了另一个环境变量 IBUS_USE_PORTAL(https://github.com/ibus/ibus/blob/d9ff2bb6b04a7cf7d99f4e9832b4b8905858178c/src/ibusbus.c#L493)

总而言之是能用了


登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter

| Theme: Aeros 2.0 by TheBuckmaker.com