agent-Specialization/wsl2-sandbox-poc-report.md
JOJO 42cd99d2d8 feat(windows): WSL2 沙箱执行环境与执行环境提示词平台拆分
- Windows 宿主机模式基于 WSL2 实现沙箱执行:只读/批准/自动审核识别、
  工作区可写+区外只读挂载、网络档位(受限/开放/禁止)、敏感目录屏蔽
- 新增 scripts/setup-wsl-sandbox.ps1 一键准备 WSL 沙箱发行版
- 执行环境提示词按平台拆分骨架:prompts/execution_mode/macos.txt
  (原 execution_mode.txt,mac/dockerweb 沿用)与 windows.txt
  (骨架+动态注入环境与路径、当前规则、网络档位、切换一致性说明)
- Windows 执行环境切换通知改为完整命令写法说明(双向),mac 保持原样
- 附调研与 PoC 验证报告:wsl2-sandbox-research.md、
  windows-sandbox-research.md、wsl2-sandbox-poc-report.md
2026-07-30 13:06:34 +08:00

91 lines
6.3 KiB
Markdown
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# WSL2 + bwrap 沙箱概念验证PoC实验报告
> 日期2026-07-30 · 实验机Windows 11 (26200) · WSL2 内核 5.15.167.4
> 结论先行:**路线可行,隔离强度达到调研预期,可以进入源码改造。**
> 前提条件:必须使用专用发行版并关闭 Windows 互操作interop否则存在沙箱逃逸见 E8
## 1. 实验环境搭建(已验证的部署流程)
```cmd
:: 1. 下载 Alpine minirootfs~3.5MB
curl -L -o alpine-minirootfs.tar.gz https://dl-cdn.alpinelinux.org/alpine/v3.21/releases/x86_64/alpine-minirootfs-3.21.3-x86_64.tar.gz
:: 2. 导入为专用沙箱发行版(非交互,可编程)
wsl --import astrion-sandbox <安装目录> alpine-minirootfs.tar.gz --version 2
:: 3. 发行版内配置(详见 §3 的发现)
:: - /etc/wsl.conf: [interop] enabled=false / appendWindowsPath=false[network] generateResolvConf=false
:: - /etc/resolv.conf: 固定公共 DNS223.5.5.5 / 119.29.29.29
:: - /etc/apk/repositories: 换国内镜像mirrors.aliyun.com
:: - apk add bubblewrap bash ncurses-libs python3 git
```
## 2. 实验结果总表24 项23 PASS / 1 INFO
沙箱命令模板(与项目现有 `_build_linux_common_plan` 同构):
```
只读模式: bwrap --die-with-parent --new-session --unshare-all --share-net \
--ro-bind / / --ro-bind <ws> <ws> --chdir <ws> \
--proc /proc --dev /dev --tmpfs /tmp -- bash -lc <cmd>
工作区可写: 同上,工作区改为 --bind <ws> <ws>
网络全禁/仅回环: 去掉 --share-net--unshare-all 自带的 unshare-netlo 自动可用)
```
| 分组 | 实验 | 结果 | 说明 |
|---|---|---|---|
| E0 基础 | 发行版执行 / bwrap 0.11 / user namespace | ✅ | WSL2 满足 bwrap 全部前提 |
| E0 路径 | `E:\...``/mnt/e/...` 转换 + 工作目录 | ✅ | 机械转换即可,含空格路径正常 |
| E0 编码 | `WSL_UTF8=1` 解决 wsl.exe UTF-16 乱码 | ✅ | 必须设置 |
| E0 输出 | localhost 代理警告仅在 stderr | ✅ | 可在执行器层过滤 |
| E1 只读 | 工作区内写入 → `Read-only file system` | ✅ | 报错关键词与 mac 语义一致,审批关键词匹配可直接复用 |
| E1 只读 | 系统/工作区读取正常 | ✅ | |
| E1 只读 | 写 Linux 系统目录被拒 | ✅ | |
| E1 只读 | **写工作区外 Windows 盘9P 子挂载)被拒** | ✅ | 关键项ro-bind / 对 9P 挂载同样生效 |
| E2 可写 | 工作区内写入真实落盘 Windows | ✅ | |
| E2 可写 | 工作区外 Windows 盘写入被拒 | ✅ | |
| E2 可写 | Linux 系统目录写入被拒tmpfs /tmp 可写 | ✅ | 对齐 macOS /tmp 语义 |
| E3 禁读 | 未掩蔽时敏感文件可读(风险确认) | ✅ | 前置确认 |
| E3 禁读 | `--ro-bind /dev/null <file>` 掩蔽单文件 | ✅ | |
| E3 禁读 | `--tmpfs <dir>` 掩蔽整目录 | ✅ | 可实现 macOS deny-read 等价 |
| E4 网络 | share-net 外网可达 | ✅ | |
| E4 网络 | unshare-net 外网不可达 | ✅ | |
| E4 网络 | unshare-net 下 lo 可用、127.0.0.1 实际通信 | ✅ | 等价 macOS restricted仅回环语义 |
| E5 综合 | 只读模式 `rm -rf` 工作区被拦截 | ✅ | |
| E5 综合 | 可写沙箱 `rm -rf /mnt/c/Windows/...` 全部 Read-only | ✅ | |
| E6 交互 | bwrap 内 `bash -i` stdio 逐条往返 | ✅ | 持久终端方案成立 |
| E7 性能 | 单次 wsl.exe 调用 ~950-1000ms | | 后续需长驻进程复用优化 |
| E8 工具链 | git init/add/commit 全流程、python3 写文件 | ✅ | 工作区内正常,工作区外 OSError 拒绝 |
## 3. 关键发现(实验中新暴露、调研未覆盖的)
### E8-逃逸(最严重):必须关闭 Windows interop
- **未关闭时**:只读 bwrap 沙箱内执行 `cmd.exe /c echo pwned > E:\...\file.txt` **成功写入 Windows 盘**。interop 进程由 WSL 会话 init 在命名空间外拉起bwrap 完全管不到 → 沙箱形同虚设。
- **封堵方式**(已验证):专用发行版 `/etc/wsl.conf``[interop] enabled=false` + `appendWindowsPath=false`,重启发行版后 `cmd.exe: command not found`,逃逸封死。
- 结论:沙箱发行版必须是**专用、受控配置**的,绝不能复用用户自己的 Ubuntu 等发行版。Claude Code 的 WSL 沙箱同样禁 interop属行业共识做法。
### 网络环境适配(本机实测暴露)
- 宿主使用 localhost 代理时WSL NAT 模式的 DNS 转发10.255.255.254 → 宿主解析器)**会失效**(时好时坏);直连公共 DNS223.5.5.5)正常 → 发行版需固化 `generateResolvConf=false` + 公共 DNS。
- apk 官方源大包下载会卡死,换阿里云镜像后秒装 → 发行版应内置国内镜像(或做成可配置)。
- wsl.exe 每次启动都在 stderr 打 localhost 代理警告 → 执行器需过滤 stderr 该行(或在 `.wslconfig` 全局设 `autoProxy=false`,影响面大,不推荐默认做)。
### 工程细节
- Git Bash 调用 wsl.exe 会被 MSYS2 路径转换毁掉 Unix 参数(`/etc/...` → `E:/KimiData/...`)→ 仅影响开发调试(设 `MSYS2_ARG_CONV_EXCL='*'`Python subprocess 不受影响。
- `bash` 需显式安装Alpine 默认 busybox sh且需 `ncurses-libs` 才能跑。
## 4. 与 macOS 沙箱的能力对照(最终形态)
| 能力 | macOS现状 | Windows WSL2+bwrapPoC 验证后) |
|---|---|---|
| 只读模式 | sandbox-exec deny-write | bwrap 全 ro-bind ✅ |
| 工作区可写 | profile writable paths | ro-bind / + bind ws ✅ |
| 敏感路径禁读 | deny subpath / regex | tmpfs/dev-null 掩蔽(无 regex需逐个路径 |
| 网络三档 | profile 网络规则 | share-net / unshare-netrestricted≈仅回环✅ |
| 审批链语境 | Unix 报错关键词 | 完全一致Read-only file system / Permission denied✅ |
| 只读命令白名单 | Unix 命令集 | 完全一致(同为 Linux bash✅ |
| 交互终端 | sandbox-exec bash -i | bwrap bash -i ✅ |
遗留限制(二期):单次调用 ~950ms 开销需长驻 WSL 进程复用;禁读不支持 regex可改为启动前枚举 .env 类文件逐个掩蔽seccomp 过滤器暂未接入bwrap 本身已满足 FS/网络隔离需求)。
## 5. 原始实验日志
完整 24 项原始输出见 `.wsl-poc/results.md`(含 E5.2 逐文件 Read-only 报错洪流,可佐证 9P 挂载保护的真实性)。实验脚本:`.wsl-poc/run_experiments.sh`。