containers/bubblewrap

GitHub: containers/bubblewrap

一个轻量级的 Linux 非特权沙箱工具,通过 setuid 实现用户命名空间的安全子集,让普通用户无需 root 即可创建隔离的进程环境。

Stars: 5964 | Forks: 287

# Bubblewrap 许多容器运行时工具,如 `systemd-nspawn`、`docker` 等,专注于为系统管理员和编排工具(例如 Kubernetes)提供运行容器的基础设施。 这些工具不适合提供给非特权用户,因为将此类访问权限转化为宿主机上完全特权的 root shell 是轻而易举的。 ## User namespaces Linux 内核中有一项名为 [user namespaces](https://www.google.com/search?q=user+namespaces+site%3Ahttps%3A%2F%2Flwn.net) 的工作,旨在允许非特权用户使用容器功能。 尽管已经取得了重大进展,但仍存在 [一些顾虑](https://lwn.net/Articles/673597/),并且在 CentOS/Red Hat Enterprise Linux 7、Debian Jessie 等多个生产发行版中,非特权用户无法使用该功能。 例如,参见 [CVE-2016-3135](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-3135),这是由 userns 引入的一个本地 root 漏洞。[这篇 2016 年 3 月的文章](https://lkml.org/lkml/2016/3/9/555) 有更多的讨论。 Bubblewrap 可以被视为 user namespaces *子集* 的 setuid 实现。重点在于“子集”——具体针对上述 CVE 而言,bubblewrap 不允许控制 iptables。 最初的 bubblewrap 代码早于 user namespaces——它继承了 [xdg-app helper](https://cgit.freedesktop.org/xdg-app/xdg-app/tree/common/xdg-app-helper.c?id=4c3bf179e2e4a2a298cd1db1d045adaf3f564532) 的代码,而后者又远源于 [linux-user-chroot](https://git.gnome.org/browse/linux-user-chroot)。 ## 系统安全 该工具的维护者认为,即使在结合该发行版上安装的典型软件使用时,它也不允许权限提升。然而,它可能会增加登录用户执行拒绝服务攻击的能力。 特别是,bubblewrap 使用 `PR_SET_NO_NEW_PRIVS` 来关闭 setuid 二进制文件,这是逃逸 chroot 之类环境的[传统方式](https://en.wikipedia.org/wiki/Chroot#Limitations)。 ## 沙箱安全 bubblewrap 是用于构建沙箱环境的工具。 bubblewrap 不是具有特定安全策略的完整、现成的沙箱。 bubblewrap 的一些用例需要在沙箱和真实系统之间建立安全边界;其他用例则希望更改沙箱内进程的文件系统布局,但并不旨在成为安全边界。 因此,沙箱进程与宿主系统之间的保护级别完全取决于传递给 bubblewrap 的参数。 任何为 bubblewrap 构建命令行参数的程序(通常是像 Flatpak、libgnome-desktop、sandwine 这样的较大框架或临时脚本)都有责任定义其自身的安全模型,并选择适当的 bubblewrap 命令行参数来实现该安全模型。 需要特别留意的沙箱安全方面在下面的 [Limitations](#limitations) 章节中进行了描述。 ## 用户 该程序可以被所有执行非 root 操作的容器工具共享,例如: - [Flatpak](https://www.flatpak.org) - [rpm-ostree unprivileged](https://github.com/projectatomic/rpm-ostree/pull/209) - [bwrap-oci](https://github.com/projectatomic/bwrap-oci) 我们还希望能在 Kubernetes/OpenShift 集群中使用它。非特权用户拥有使用容器功能的能力将使执行交互式调试场景等任务变得显著更容易。 ## 安装 bubblewrap 可在大多数 Linux 发行版的软件包仓库中找到,并可以从那里安装。 如果您需要从源代码构建 bubblewrap,可以使用 meson: ``` meson _builddir meson compile -C _builddir meson test -C _builddir meson install -C _builddir ``` ## 用法 bubblewrap 的工作原理是创建一个新的、完全空的 mount namespace,其根目录位于一个从宿主机不可见的 tmpfs 上,并且会在最后一个进程退出时自动清理。然后,您可以使用命令行选项来构建根文件系统和进程环境,以及在 namespace 中运行的命令。 源代码中有一个更大的 [demo script](./demos/bubblewrap-shell.sh),但这里有一个精简版,它运行一个重用宿主机 `/usr` 的新 shell。 ``` bwrap \ --ro-bind /usr /usr \ --symlink usr/lib64 /lib64 \ --proc /proc \ --dev /dev \ --unshare-pid \ --new-session \ bash ``` 这是一个不完整的示例,但对于说明目的很有用。更多情况下,您不是使用宿主机的文件系统树创建容器,而是针对一个 chroot。在这种情况下,您可能已经在目标 rootfs 中创建了符号链接 `lib64 -> usr/lib64`,而不是在 tmpfs 中创建它。 ## 沙箱机制 bubblewrap 的目标是在沙箱中运行应用程序,在该沙箱中,它对操作系统部分或用户数据(如主目录)的访问受到限制。 bubblewrap 总是创建一个新的 mount namespace,用户可以确切地指定文件系统的哪些部分应该在沙箱中可见。 您指定的任何此类目录默认以 `nodev` 方式挂载,并且可以设为只读。 此外,您可以使用以下内核功能: User namespaces ([CLONE_NEWUSER](https://linux.die.net/man/2/clone)):这会向沙箱隐藏除当前 uid 和 gid 之外的所有信息。您还可以更改沙箱中 uid/gid 的值。 IPC namespaces ([CLONE_NEWIPC](https://linux.die.net/man/2/clone)):沙箱将获得所有不同形式 IPC 的副本,例如 SysV 共享内存和信号量。 PID namespaces ([CLONE_NEWPID](https://linux.die.net/man/2/clone)):沙箱将看不到沙箱之外的任何进程。此外,bubblewrap 将在您的容器内运行一个微不足道的 pid1,以处理在沙箱中回收子进程的要求。这避免了现在被称为 [Docker pid 1 problem](https://blog.phusion.nl/docker-and-the-pid-1-zombie-reaping-problem/) 的问题。 Network namespaces ([CLONE_NEWNET](https://linux.die.net/man/2/clone)):沙箱将看不到网络。相反,它将拥有自己的网络 namespace,其中只有一个 loopback 设备。 UTS namespace ([CLONE_NEWUTS](https://linux.die.net/man/2/clone)):沙箱将拥有自己的主机名。 Seccomp 过滤器:您可以传入 seccomp 过滤器,以限制在沙箱中可以执行哪些系统调用。有关更多信息,请参阅 [Seccomp](https://en.wikipedia.org/wiki/Seccomp)。 ## 限制 正如上面的 [Sandbox security](#sandbox-security) 章节所述,沙箱进程与宿主系统之间的保护级别完全取决于传递给 bubblewrap 的参数。 此处列出了需要特别注意的一些方面。 - 如果您没有使用 seccomp 过滤器过滤掉 `TIOCSTI` 命令,则需要参数 `--new-session` 来防止沙箱外命令执行(参见 [CVE-2017-5226](https://github.com/containers/bubblewrap/issues/142))。 - 挂载到沙箱中的任何内容都可能被用于提升权限。 例如,如果您将 D-Bus 套接字绑定到沙箱中,它可用于通过 systemd 执行命令。您可以使用 [xdg-dbus-proxy](https://github.com/flatpak/xdg-dbus-proxy) 来过滤 D-Bus 通信。 - 某些应用程序部署了自己的沙箱机制,这些机制可能会受到 bubblewrap 沙箱所施加的约束的限制。 例如,某些 Web 浏览器通过 seccomp 将其子进程配置为无权访问文件系统。如果您限制了系统调用且不允许 seccomp 系统调用,浏览器将无法应用这些限制。 同样,如果这些规则被编译成一个在沙箱中不可用的文件中,浏览器将无法从该文件加载这些规则,也无法应用这些限制。 ## 相关项目比较:Firejail [Firejail](https://github.com/netblue30/firejail/tree/HEAD/src/firejail) 类似于 bubblewrap 分离之前的 Flatpak,因为它结合了 setuid 工具和许多特定于桌面的沙箱功能。例如,Firejail 了解 Pulseaudio,而 bubblewrap 不了解。 bubblewrap 作者认为审计小型 setuid 程序要容易得多,并且将 Pulseaudio 过滤等功能保留为非特权进程(正如现在 Flatpak 中所做的那样)。 此外,@cgwalters 认为试图 [白名单文件路径](https://github.com/netblue30/firejail/blob/37a5a3545ef6d8d03dad8bbd888f53e13274c9e5/src/firejail/fs_whitelist.c#L176) 是个坏主意,因为用户有多种操作路径的方式,而且系统管理员也有多种配置系统的方式。bubblewrap 方法是仅保留少数特定的 Linux capabilities(如 `CAP_SYS_ADMIN`),但始终以调用 uid 的身份访问文件系统。这完全杜绝了 [TOCTTOU attacks](https://cwe.mitre.org/data/definitions/367.html) 之类的攻击。 ## 相关项目比较:Sandstorm.io [Sandstorm.io](https://sandstorm.io/) 需要非特权 user namespaces 来设置其沙箱,尽管它也可以很容易地适应在 setuid 模式下运行。@cgwalters 相信他们的代码相当不错,但统一使用 bubblewrap 可能仍然是有意义的。 然而,@kentonv(来自 Sandstorm)认为,虽然这在原则上是有道理的,但切换成本目前超过了实际收益。将来可以重新评估此决定,但目前并未积极开展相关工作。 ## 相关项目比较:runc/binctr [runC](https://github.com/opencontainers/runc) 目前正在致力于支持 [rootless containers](https://github.com/opencontainers/runc/pull/774),即在安装 runC(使用非特权 user namespaces 而不是 `setuid`)、创建和管理容器期间不需要 `setuid` 或任何其他权限。然而,使用 runC 的标准模式类似于 [systemd nspawn](https://www.freedesktop.org/software/systemd/man/systemd-nspawn.html),因为它是旨在由 root 调用的工具。 bubblewrap 作者认为 runc 和 systemd-nspawn 并非设计为 setuid,并且距离支持此类模式还很遥远。 然而,对于 rootless containers,runC 将能够满足 bubblewrap 支持的某些用例(其附加优势是作为标准化且完整的 OCI runtime)。 [binctr](https://github.com/jfrazelle/binctr) 只是 runC 的包装器,因此继承了其所有设计权衡。 ## 这名字是什么意思?! 选择 bubblewrap 这个名称是为了传达该工具作为应用程序的父进程运行(因此在某种意义上将其包裹)并围绕它创建一个保护层(沙箱)。 ![](https://static.pigsec.cn/wp-content/uploads/repos/2026/03/5410a35143155056.jpg) (Bubblewrap cat by [dancing_stupidity](https://www.flickr.com/photos/27549668@N03/))
标签:Bubblewrap, CSV导出, Flatpak, Linux沙箱, setuid, Web截图, 子域名枚举, 客户端加密, 客户端加密, 容器安全, 应用沙盒, 底层工具, 权限控制, 沙箱, 渗透测试框架, 特权分离, 用户命名空间, 系统安全, 网络安全审计, 配置错误, 防御, 隔离技术, 非特权容器, 预握手