首页
/ openinterpreter 仓库中的 bubblewrap 源码:NEWS 版本演进、setuid 弃用与在 Linux 沙箱中的编译集成

openinterpreter 仓库中的 bubblewrap 源码:NEWS 版本演进、setuid 弃用与在 Linux 沙箱中的编译集成

2026-09-06 17:24:16作者:宗隆裙

本文以 codex-rs/vendor/bubblewrap/NEWS.md 这份 vendored 变更日志为主线,梳理 bubblewrap 0.11.0 → 0.11.2 三个版本的完整改动(安全修复、-Dsupport_setuid 构建开关、overlay 支持等),并结合本仓库的实际构建代码(Cargo 构建脚本、Bazel 规则)与 codex-linux-sandbox 的运行机制,说明这份 vendored 源码是如何被直接编译进项目的 Linux 沙箱执行链路的。读完后,你将能准确理解各版本条目的技术含义、setuid 模式为何被默认关闭,以及当系统未安装 bwrap 时 bundled 二进制从哪里来。

NEWS.md:vendored bubblewrap 的完整变更日志

bubblewrap(命令名 bwrap)是 Linux 下基于命名空间与 seccomp 的轻量沙箱工具,在仓库中它以完整 C 源码的形式被 vendor 到 codex-rs/vendor/bubblewrap/ 目录下(含 bubblewrap.cbind-mount.cnetwork.cutils.c 及头文件、测试、shell 补全脚本等)。codex-rs/vendor/bubblewrap/NEWS.md 就是这份 vendored 源码的版本变更记录,覆盖 0.11.0 至 0.11.2 三个发布版本。文档末尾的 "See also" 指向上游 releases 页面(外部链接,此处按规范不输出),版本事实以本仓库内文件为准。

0.11.2(2026-04-23):setuid 漏洞修复与 -Dsupport_setuid 构建开关

这是 vendored 版本中的最新版本,包含一项安全修复和一项构建增强:

Bug fix:CVE-2026-41163(setuid 模式下的 ptrace 问题)

在 setuid 模式下,bubblewrap 会先以高权限完成部分 setup,再降权执行其余部分。0.11.2 之前的实现会让低权限阶段的进程保持 dumpable 状态,这意味着该进程仍可被 ptrace,从而带来安全隐患(由 François Diakhate 报告,编号 CVE-2026-41163)。修复方式是让 setuid 模式的低权限部分不再以 dumpable 身份运行,直接消除这条被 ptrace 的路径。

Enhancement:新的 Meson 选项 -Dsupport_setuid(默认 false

当该选项设为 false(默认值)时,编译出的二进制将完全禁用 setuid 支持,并且如果被人为设置为 setuid 权限会直接拒绝运行。NEWS 原文明确推荐:普通用户就应该用这种方式构建 bubblewrap,这样可以把只影响 setuid 模式的安全问题安全地排除在威胁模型之外。

这一点在本仓库中有直接的代码印证:codex-rs/vendor/bubblewrap/meson_options.txt 第 44–49 行定义了该选项:

option(
  'support_setuid',
  type : 'boolean',
  description : 'Support setuid mode (deprecated)',
  value : false,
)

可以看到 support_setuid 被标注为 deprecated 且默认 false,与 NEWS 条目完全一致。这也解释了本仓库整体策略——codex-linux-sandbox 走的是用户命名空间(--unshare-user)而非 setuid 的路径(详见下文),因此 setuid 相关漏洞面与本项目的运行时风险基本解耦。

0.11.1(2026-03-21):SIGCHLD 处置恢复与命名空间 fd 参数修复

Bug fix:重置 SIGCHLD 的处置(#705)

当 bwrap 从一个正在忽略 SIGCHLD 的父进程(例如 Erlang 运行时、volumeicon 这类常驻 GUI 进程)内部启动时,之前不会恢复该信号的标准处置,导致容器内子进程管理行为异常。0.11.1 会显式重置 SIGCHLD disposition,恢复正常的子进程管理语义。对于任何在忽略 SIGCHLD 的宿主进程中派生沙箱命令的场景,这是一项重要的行为修复。

Bug fix:不再忽略显式传入的 --userns 0 / --userns2 0 / --pidns 0(#731)

此前把 fd 号 0 传给 --userns/--userns2/--pidns 会被当作"未指定"而忽略。修复后这些参数会被如实处理。NEWS 同时保留了实用提示:由于 stdin/stdout/stderr(fd 0–2)会被容器内命令继承,给这类选项传 fd ≥ 3 仍是推荐做法,以避免歧义。

其他修复:错误信息语法修正(#694)、文档中的失效链接修复(#729)。

Internal:CI 中启用 user namespaces(#728)

在 GitHub Actions 配置里显式启用 user namespaces,修复了新版 Ubuntu 上的 CI 回归。这条内部改动对下游使用者也有参考意义:bubblewrap 的用户命名空间路径依赖内核与发行版配置,CI 环境需要主动开启 userns 支持(本仓库 vendor 目录下的 codex-rs/vendor/bubblewrap/ci/enable-userns.sh 正是配套的启用脚本)。

0.11.0(2024-10-30):Meson 独占构建、overlay 挂载与 --level-prefix

这是三个版本中改动量最大的一版,横跨构建系统、功能增强与修复:

Dependencies:Autotools 移除,Meson ≥ 0.49.0 成为构建期硬性要求(#625)

Autotools 构建系统被彻底删除,构建只走 Meson。对 bash 补全用户的额外要求:推荐 bash-completion ≥ 2.10;更老的 bash-completion 版本可能把补全脚本安装到 ${prefix} 之外,此时可用 -Dbash_completion_dir=… 覆盖安装目录。codex-rs/vendor/bubblewrap/meson_options.txt 中的 bash_completion / bash_completion_dir / zsh_completion / zsh_completion_dir 等选项定义与这条说明一一对应。

Enhancement:overlay 挂载四件套(#412、#663)

新增 --overlay--tmp-overlay--ro-overlay--overlay-src 四个选项,用于创建 overlay 挂载。NEWS 明确注明:当 bubblewrap 以 setuid 方式安装时该功能不可用——这与 0.11.2 推进的"默认关闭 setuid"方向相互呼应:overlay 能力只在非 setuid(用户命名空间)路径下提供。

Enhancement:--level-prefix 选项(#646)

输出可被 logger --prio-prefixsystemd-cat --level-prefix=1 等工具解析的带级别前缀的日志,方便把 bwrap 日志接入 systemd/journald 体系。

Bug fixes 一览

  • 对文件与套接字的 I/O 处理 EINTR(#657):被信号中断的读写不再直接失败,改善长 I/O 场景的健壮性;
  • 不再假设 socket 控制消息(recvmsg cmsg)数据的对齐方式(#637):提升跨架构可移植性;
  • 消除部分 Meson 弃用警告(#647);
  • 文档 URL 全部升级为 https(#566);
  • 提升测试对 busybox 的兼容性(#627);
  • 改进对 Meson < 1.3.0 的兼容(#664)。

Internal changes:统一使用 <stdbool.h> 表示布尔值(#660)、规避 -Wshadow 告警(#661)、更新 GitHub Actions 配置(#658)。

仓库如何编译这份 vendored 源码:双构建系统集成

NEWS 描述的只是上游 bubblewrap 的版本事实;真正让这些 C 文件在项目里生效的,是本仓库的两套构建集成。理解这一层,才能知道 0.11.2 的修复"确实进入了产物"。

1. Cargo 构建路径:codex-bwrap crate

codex-rs/bwrap/ 是一个独立的 crate(包名 codex-bwrap,产物二进制名 bwrap,见 Cargo.toml),它不在运行时调用外部 bubblewrap,而是在构建期直接编译 vendored 的 C 源码。核心逻辑在 build.rs

  • 源码目录解析优先级(resolve_bwrap_source_dir,第 84–106 行):环境变量 CODEX_BWRAP_SOURCE_DIR 指向的现有 checkout 优先,否则回落到 codex-rs/vendor/bubblewrap
  • 通过 pkg-config 探测 libcap(第 37–40 行),探测失败即构建失败——这与 NEWS 中 bubblewrap 依赖 libcap 的事实一致,main.rs 里的降级提示也写明 "libcap headers must be available via pkg-config";
  • cc 编译 4 个 C 文件(bubblewrap.cbind-mount.cnetwork.cutils.c),关键编译宏是 -Dmain=bwrap_main(第 59–61 行):把 C 侧的 main 改名,让 Rust 侧的薄包装成为真正的程序入口;
  • 生成最小 config.h,内容即 PACKAGE_STRING "bubblewrap built for Codex"(第 45–49 行),bwrap --version 等输出因此能表明来源;
  • 非 Linux 目标或设置了 CODEX_SKIP_BWRAP_BUILD 时直接跳过,仅输出 cfg(bwrap_available) 检查声明,不做编译。

Rust 入口 src/main.rs 只有约 45 行:Linux 且 bwrap_available 时声明 extern "C" fn bwrap_main(argc, argv),把 std::env::args_os() 转成 NUL 结尾的 argv 指针数组后调用(第 27 行),并用其返回值作为进程退出码;未启用时直接 panic 并打印三条排查提示(目标 OS 必须是 Linux、libcap 头文件须可被 pkg-config 发现、vendored 源码位置)。也就是说,cargo build 得到的 bwrap 二进制就是上游 C 实现的直接链接产物,版本行为与 NEWS 中 0.11.x 的描述严格对应。

2. Bazel 构建路径:cc_library + filegroup

Bazel 侧不走 Cargo 的 build.rsbuild_script_enabled = False),而是用原生规则拼接,见 codex-rs/bwrap/BUILD.bazel

  • cc_library(name = "bwrap-ffi") 直接以 //codex-rs/vendor:bubblewrap_c_sourcessrcs(即 vendor/BUILD.bazelglob(["bubblewrap/*.c"]) 的 filegroup),copts-D_GNU_SOURCE-Dmain=bwrap_maindeps = ["@libcap"],且 target_compatible_with = ["@platforms//os:linux"]——与 Cargo 路径的编译宏、平台限制完全对齐;
  • codex_rust_crate 通过 select 在 Linux 上追加 :bwrap-ffi 依赖并注入 --cfg=bwrap_available,非 Linux 平台则该 cfg 不存在,main.rs 自动落入 panic 分支。

两条路径殊途同归:同一个 vendored 源码树,同一套改名 main 的手法,同一份 libcap 依赖,保证 Cargo 与 Bazel 两种发行方式下 bwrap 的行为一致。

与运行时的关系:bundled bwrap 在 codex-linux-sandbox 中的角色

NEWS 里 0.11.1 的 userns/pidns fd 修复、0.11.0 的 EINTR 处理,最终都服务于一个事实:本仓库的沙箱层几乎全程通过 bwrap 的用户/ PID/网络命名空间能力工作。codex-rs/linux-sandbox/README.md 给出了选择策略与默认行为(引自原文要点):

  • Bubblewrap 是默认的文件系统沙箱。优先使用 PATH 上(当前工作目录之外)找到的系统 bwrap;若版本过旧不支持 --argv0,会走一条不含 --argv0 的内层 re-exec 兼容路径;若 bwrap 缺失,则回落到随产品分发的 bundled codex-resources/bwrap——即上一节构建出的 vendored 二进制;
  • bwrap 缺失或无法创建 user namespace 时,启动阶段即给出警告,而不是等到运行时才失败。这与 0.11.1 在 CI 中主动启用 userns 的内部改动形成呼应:userns 支持是整条沙箱链路的先决条件;
  • 具体挂载与隔离方式:默认以 --ro-bind / / 让文件系统整体只读,可写根目录用 --bind <root> <root> 分层叠加;受保护子路径(如 .git.codex)再以 --ro-bind 恢复只读;显式 --unshare-user--unshare-pid 隔离用户/PID 命名空间,网络受限且无代理路由时追加 --unshare-net;默认 --proc /proc 挂载全新 /proc(严格容器环境可用 --no-proc 跳过);bubblewrap 激活时在进程内施加 PR_SET_NO_NEW_PRIVS 与 seccomp 网络过滤器;
  • 平台边界:WSL2 走正常 Linux bubblewrap 路径;WSL1 因无法创建所需用户命名空间,Codex 会在进入 bubblewrap 路径前直接拒绝需要沙箱的 shell 命令。

此外 0.11.0 新增的 --overlay 系列选项在本仓库当前沙箱实现中未见直接使用(README 描述的挂载组合仍以 --ro-bind/--bind 为主),可视为上游提供的能力储备而非现有代码路径。

安全视角小结:为什么"默认无 setuid"对本仓库至关重要

把 NEWS 的三个版本串起来看,有一条清晰的主线:bubblewrap 0.11.x 系列持续收缩 setuid 攻击面——0.11.2 修复 setuid 模式下的 CVE-2026-41163、并让 -Dsupport_setuid=false(默认)构建出的二进制拒绝以 setuid 身份运行;0.11.0 的 overlay 功能也声明在 setuid 安装下不可用。而本仓库的运行时恰好只依赖用户命名空间路径(--unshare-user + userns 可用性检测 + WSL1 直接拒绝),构建侧又始终编译非 setuid 的二进制。可以推断:对于跟随本仓库构建产物的用户,NEWS 中所有"only affect setuid mode"的条目基本不构成实际风险,这正是 0.11.2 推荐构建方式与项目沙箱策略的天然契合。

延伸阅读(仓库内路径)

登录后查看全文
热门项目推荐
相关项目推荐