feat(sandbox): am-sandbox —— 给命令套 Landlock 内核边界(界内可写、界外 EACCES)
「工作区档」此前名不副实:档位表写「本目录内可动、越界要问人」,而 pi 这一路只能按 **工具名**判(bash/write/edit 一律问人),因为命令的影响范围无法从文本静态判定 (`cd /工作区 && rm -rf /opt/x` 以"进工作区"开头)。pi 自己**故意**不内置沙箱 (docs/security.md §No Built-in Sandbox:进程内的部分沙箱会被误解成安全边界, "Real isolation needs to come from the operating system or a container boundary")—— dsh 是把沙箱放进自己的运行时;这个二进制补的是 pi 这一侧的**宿主**部分。 ## 语义 写:只有 `--rw` 列出的目录(含子树)与 `--rw-file` 列出的文件可写,其余写操作一律 EACCES(内核判)。读与执行不限制 —— Landlock 只做白名单式加法,要连读都挡住得靠 容器/挂载命名空间。套不上边界时 **fail closed**(退出码 126,不执行命令):静默裸跑 会让"档位=workspace"变成谎话,而谎话比做不到更危险。 ## 判据 - 行为 `deploy/check-sandbox.sh`:19 项全绿 —— 界内可写/子目录递归/rename+删除、 读界外、执行、写 /dev/null;界外新建/建目录/覆盖/删除/删目录/跨边界 rename/ 软链接逃逸/子进程继承;**对照**(不套边界时那些"必须被拒"的命令必须成功,否则 判据可能只是环境本来就只读);fail-closed 那条(rw 不存在 ⇒ 126 且命令未执行)。 - 算法 `cmd/am-sandbox` 单测:按 ABI 逐位裁剪、文件目标不得带目录类权限、 allowed ⊂ handled、参数解析。 ## 过程中撞到两个"看着能过"的坑 1. `--rw-file` 任意文件 → add_rule **EINVAL**:文件目标只能用文件类权限 (MAKE_*/REMOVE_*/REFER 是目录类),而错误信息只有 "invalid argument", 看不出是权限位不匹配。单测里"文件权限必须是 handled 的子集"就是拦它的。 2. ★ 判据自己翻车:`"$SB" … 2>&1 | grep -q "Permission denied"` 在 `set -o pipefail` 下 —— **grep 命中即退出 → 左侧 EPIPE 失败 → 整条管道判失败** ⇒ 7 条"界外必须被拒"全被判成"没被拒"。改成先收输出再匹配,顺带打印真实输出。 ## 已知边界(写进文件头 + 判据输出留痕,不假装没有) - 元数据(chmod/chown/utimes)不受 Landlock 管辖:界外文件**内容**改不了, 但**模式位**能改 - 网络出向不受限 - 界内**已存在**的、指向界外文件的硬链,经界内路径写入会改到界外(路径式沙箱固有) - 本机 ABI=2(无 TRUNCATE);实测 `truncate` 越界仍被拒(coreutils 先 open 写 ⇒ WRITE_FILE 挡住),所以那个缺口比纸面上窄 - **读不限制** ⇒ 以 root 跑的 agent 仍能读整机(含 /etc/agentmail/*.env)。沙箱在这里 的价值是"界外留不下脚印",不是"拿不到东西" —— 要后者得上容器 ## 接线 `redeploy-gateway.sh` / `install.sh` 在**边界判据真跑绿了**之后才装到 `/opt/agentmail/bin/am-sandbox`(装一个套不上边界的工具等于发空头支票)。 pi 桥的接线(按档位把 worker 套进边界)还没做 —— 见随后的报告。
This commit is contained in:
@ -379,6 +379,19 @@ echo "==> 安装 systemd 单元"
|
||||
# 源码目录(旧版 ExecStart 指向 /home/program/agentmail/plugins/...)。
|
||||
install -d "$PREFIX/bin"
|
||||
install -m 0755 "$REPO/deploy/service-failure-notify.mjs" "$PREFIX/bin/service-failure-notify.mjs"
|
||||
|
||||
# 边界工具(Landlock 沙箱):只有本机能真建立边界时才装。理由与判据见
|
||||
# redeploy-gateway.sh 同一段(am-sandbox 自己 fail closed,装个用不了的工具
|
||||
# 等于给"档位=workspace"发空头支票)。
|
||||
SANDBOX_STAGE="$(mktemp -d)/am-sandbox"
|
||||
if ( cd "$REPO/server" && go build -trimpath -o "$SANDBOX_STAGE" ./cmd/am-sandbox ) \
|
||||
&& AM_SANDBOX="$SANDBOX_STAGE" bash "$REPO/deploy/check-sandbox.sh" >/tmp/am-sandbox-check.log 2>&1; then
|
||||
install -m 0755 "$SANDBOX_STAGE" "$PREFIX/bin/am-sandbox"
|
||||
echo " 边界工具已装(判据 $(grep -c '\[ OK \]' /tmp/am-sandbox-check.log) 项全绿)"
|
||||
else
|
||||
echo " [警告] 本机建立不起 Landlock 边界:不装 am-sandbox(见 /tmp/am-sandbox-check.log)" >&2
|
||||
fi
|
||||
rm -f "$SANDBOX_STAGE"
|
||||
while IFS= read -r f; do
|
||||
rel="${f#"$REPO/deploy/systemd/"}"
|
||||
install -D -m 0644 "$f" "/etc/systemd/system/$rel"
|
||||
|
||||
Reference in New Issue
Block a user