Skip to content

fix(sandbox): 将 outbox 移出 home overlay#403

Open
DeepColds wants to merge 6 commits into
masterfrom
fix/sandbox-outbox-vartmp
Open

fix(sandbox): 将 outbox 移出 home overlay#403
DeepColds wants to merge 6 commits into
masterfrom
fix/sandbox-outbox-vartmp

Conversation

@DeepColds

@DeepColds DeepColds commented Jul 8, 2026

Copy link
Copy Markdown
Collaborator

改了什么

  • 将 sandbox relay outbox 从 <dataDir>/sandboxes/<sid>/outbox 移到 /var/tmp/botmux-sbx-<uid>/<sid>/outbox
  • prepareSandbox()BOTMUX_SEND_RELAY 和 bwrap outbox bind 都使用新路径。
  • /var/tmp 下的 sandbox root 改为按 Unix uid 隔离,避免共享 Linux 机器上第一个用户创建全局 0700 目录后阻塞其他用户。
  • /var/tmp/botmux-sbx-<uid><sid>outbox 创建/reattach 时显式收紧到 0700;relay 内容、附件、视频、视频封面、请求、响应文件显式写成 0600
  • ensurePrivateDir() 加固为 fail-closed:拒绝 symlink / 非目录,校验 owner 是当前 daemon uid,再收紧并检查 mode。
  • .req.json relay 请求文件改为安全读取:O_NOFOLLOW | O_NONBLOCK 打开,fstat().isFile() 校验 regular file,64KB 上限读取后再 JSON.parse,避免 FIFO/symlink/special file/超大文件卡住 worker 或越界读取。
  • 兼容最新 master 的视频预览发送能力:sandbox relay 会透传 videos / videoCovers,并保持 master 的 --videos / --video-covers 语义,同时对这些 outbox 文件应用 0600 权限硬化。
  • attachSandboxOutbox() 优先 reattach 新 outbox,并兼容 fallback 到旧的 /var/tmp/botmux-sbx/<sid>/outbox<dataDir>/sandboxes/<sid>/outbox,避免升级时已有 sandbox session 失联。
  • sandboxedClaudeDataDir() 对升级前已在运行的 persistent sandbox 增加 legacy HOME upper fallback:当旧 /var/tmp/botmux-sbx/<sid>/home-upper 存在且新路径不存在时,Claude bridge 继续指向旧 upper。
  • cleanup / reclaim 同时 best-effort 删除新旧 vartmp sid 目录,避免旧 /var/tmp/botmux-sbx/<sid> residue 残留。
  • 更新 docs/file-sandbox.md:同步 overlay 模型、/var/tmp/botmux-sbx-<uid>/<sid>/outbox、权限策略、legacy fallback 规则,并修正凭据说明:relay 不注入发送凭据;磁盘上的 botmux 配置/密钥如需隐藏需配置 sandboxHidePaths / read isolation。
  • 增加单测覆盖 per-uid vartmp root、新 outbox 路径、legacy vartmp/dataDir fallback、legacy HOME upper bridge fallback、目录 mode、symlink 拒绝、.req.json FIFO/symlink/超限拒绝、watcher 对非法 request 写 rejected res、BOTMUX_SEND_RELAY/bwrap bind 路径、relay payload 文件 mode,以及视频/视频封面 relay 校验。

为什么

在部分 DevBox 上,sandbox 当前布局会先把整个 HOME 做 overlay 后挂回 HOME,再把 outbox bind 到 HOME 内部:

home-merged -> /data00/home/<user>
<dataDir>/sandboxes/<sid>/outbox -> /data00/home/<user>/.botmux/data/sandboxes/<sid>/outbox

<dataDir> 位于 HOME 下时,这会形成 “HOME overlay 内部再 bind 子目录” 的嵌套挂载组合。实测该组合会导致 bwrap 卡在挂载阶段,表现为进程树只有 bwrap -> bwrap,没有真正 exec 到 Traex/node;将最终命令替换成 /bin/true 也仍然超时。

把 outbox 放到 /var/tmp/botmux-sbx-<uid>/<sid>/outbox 后,它不再位于 HOME overlay 内部,可以避免该嵌套 bind 卡死。由于 /var/tmp 是共享多用户路径,本 PR 同时做多层处理:root 按 uid 拆分,避免多用户争抢一个全局 0700 目录;每个用户自己的 root/session/outbox 继续收紧为 0700,relay 文件为 0600;对已存在目录校验 symlink 和 owner;对 outbox 内的 request/content/attachment 都按 sandbox 不可信输入做 no-follow、non-blocking、regular-file 校验。

影响面

  • 影响 sandbox backend 的共用逻辑,所有 CLI 开启 sandbox 时都会使用新 outbox 路径。
  • 项目写隔离不变:仍使用 <dataDir>/sandboxes/<sid>/proj-upper
  • HOME 写隔离仍使用 /var/tmp 下的 upper/work,但路径从全局 /var/tmp/botmux-sbx/<sid>/home-upper 调整为 per-user /var/tmp/botmux-sbx-<uid>/<sid>/home-upper
  • relay 安全边界不变:sandbox 内 botmux send 仍只写 outbox,宿主 watcher 代发;relay 链路不通过 env/argv/IPC 给沙盒注入发送凭据。
  • 已 rebase/merge 到最新 master(含 --videos / --video-covers),relay 请求中同时保留 attachmentsvideosvideoCoversflags,且所有 relay 文件均为 0600
  • reattach 对旧 outbox 和旧 HOME upper 保留 fallback,降低升级中已有 persistent sandbox session 的兼容风险。
  • cleanup 同时清理 sessionRoot、新 per-uid vartmp sid 目录和旧全局 vartmp sid 目录。

测试验证

pnpm test -- test/sandbox.test.ts test/cli-send-hook-context.test.ts test/cli-send-dispatch.test.ts
# ✓ 3 files passed, 87 tests passed

pnpm build
# tsc + dashboard bundle 成功

@DeepColds DeepColds requested a review from deepcoldy as a code owner July 8, 2026 05:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants