惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

罗磊的独立博客
G
Google Developers Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
腾讯CDC
有赞技术团队
有赞技术团队
Vercel News
Vercel News
MongoDB | Blog
MongoDB | Blog
M
MIT News - Artificial intelligence
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
B
Blog RSS Feed
I
InfoQ
Blog — PlanetScale
Blog — PlanetScale
博客园_首页
The Cloudflare Blog
B
Blog
C
Check Point Blog
Stack Overflow Blog
Stack Overflow Blog
IT之家
IT之家
U
Unit 42
D
Docker
月光博客
月光博客
aimingoo的专栏
aimingoo的专栏
博客园 - Franky
A
About on SuperTechFans

依云's Blog

Wayfire支持不缩放Xwayland啦 - 依云's Blog 使用wayvnc远程访问无头Wayfire会话 - 依云's Blog pacfiles: 高速的 pacman -F 替代品 用 Android 手机当电脑的话筒 - 依云's Blog 使用 ffmpeg 对音频文件进行响度归一化 - 依云's Blog 使用 nftables 屏蔽大量 IP - 依云's Blog YubiKey 初体验 - 依云's Blog fcitx5 码表同步方案 - 依云's Blog 我正在使用的火狐扩展(2024年版) - 依云's Blog 使用 PipeWire 实现自动应用均衡器 如果你发现你的 OOM Killer 在乱杀进程 使用 atuin 管理 shell 命令历史 btrfs 元数据满了怎么办 btrfs 翻车记 在 nspawn 里运行 docker Linux 上的字体配置与故障排除 新的 PaddleOCR 部署方案 使用 EasyEffects 调整 Bose 音箱的体验 让离线软件真正离线 我所讨厌的网页行为 tmux 状态栏优化 Google Chrome 中的字体设置 从 getmail6 到 offlineimap 微信消息通知的困扰 Qt 的字体渲染问题 Wayfire 迁移进展(四):不那么 high 的 DPI Wayfire 迁移进展(二):Xwayland HiDPI 以及 waybar Wayfire 迁移进展 不同情况下的图形效果 Wayland 初体验
使用 bwrap 沙盒
依云 · 2021-08-12 · via 依云'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 更偏重于提供底层功能而不是完整的解决方案,具体用法可以让用户自由发挥。