65 lines
3.9 KiB
Bash
65 lines
3.9 KiB
Bash
#!/usr/bin/env bash
|
|
# 二分定位:chromium 150(trixie)在 sandbox hardening 下首调即崩(SIGTRAP,rc=133)。
|
|
# 背景:2026-07-11 pids-limit 调 1024 后,全新容器里 mmdc 仍 "Failed to launch the
|
|
# browser process: Code: null"(task 9dcae061);dbus 报错是干扰项。本脚本把线上
|
|
# docker run 的 hardening flag 逐个关掉,找到翻转成功的那一个。
|
|
#
|
|
# 用法(服务器 repo 根,需 docker 权限):
|
|
# bash deploy/sandbox/probe_chromium_bisect.sh [镜像名] # 默 zcbot-sandbox:latest
|
|
# 每个 case 跑两条:mmdc 渲一张最小图(走 wrapper 注入的 puppeteer-config)+ 直接跑
|
|
# chromium(看裸 rc:133=SIGTRAP,139=SEGV)。全程忠实复现线上 exec 路径:
|
|
# --user zcbot + HOME=/tmp(executor_docker._CONTAINER_ENV 同款)。
|
|
set -u
|
|
IMG="${1:-zcbot-sandbox:latest}"
|
|
|
|
TEST_MMDC='printf "flowchart TB\n A-->B\n" > /tmp/d.mmd; timeout 60 mmdc -i /tmp/d.mmd -o /tmp/d.png >/tmp/mmdc.log 2>&1; rc=$?; if [ -s /tmp/d.png ]; then echo "[PASS] mmdc rendered png"; else echo "[FAIL] mmdc rc=$rc"; tail -4 /tmp/mmdc.log; fi'
|
|
TEST_CHROME='timeout 30 /usr/lib/chromium/chromium --no-sandbox --headless --disable-gpu --disable-dev-shm-usage --dump-dom about:blank >/tmp/c.log 2>&1; rc=$?; if [ $rc -eq 0 ]; then echo "[PASS] chromium rc=0"; else echo "[FAIL] chromium rc=$rc (133=SIGTRAP 124=timeout)"; grep -iv "dbus\|crashpad" /tmp/c.log | tail -4; fi'
|
|
|
|
echo "===== host env ====="
|
|
docker --version
|
|
uname -r
|
|
C=$(docker ps --filter "label=zcbot.product=sandbox" --format '{{.Names}}' | head -1)
|
|
if [ -n "$C" ]; then
|
|
docker inspect "$C" --format "live container $C: pids={{.HostConfig.PidsLimit}} shm={{.HostConfig.ShmSize}} readonly={{.HostConfig.ReadonlyRootfs}} nnp={{.HostConfig.SecurityOpt}}"
|
|
else
|
|
echo "(no live sandbox container)"
|
|
fi
|
|
|
|
run_case() {
|
|
local name="$1"; shift
|
|
echo
|
|
echo "===== $name ====="
|
|
docker run --rm --user zcbot -e HOME=/tmp "$@" --entrypoint bash "$IMG" -c "$TEST_MMDC"
|
|
docker run --rm --user zcbot -e HOME=/tmp "$@" --entrypoint bash "$IMG" -c "$TEST_CHROME"
|
|
}
|
|
|
|
# 线上 pool.py 的 hardening 全款(iptables init / network 与本问题无关,不带)
|
|
FULL=(--read-only --tmpfs /tmp:exec,size=512m,mode=1777 --shm-size=512m
|
|
--cap-drop=ALL --security-opt=no-new-privileges --pids-limit=1024
|
|
--memory=2g --cpus=1.0)
|
|
|
|
run_case "0 baseline 无 hardening(预期 PASS;FAIL=镜像/chromium 本身坏)"
|
|
run_case "1 full hardening 线上同款(预期复现 FAIL)" "${FULL[@]}"
|
|
run_case "2 full 去 no-new-privileges" \
|
|
--read-only --tmpfs /tmp:exec,size=512m,mode=1777 --shm-size=512m \
|
|
--cap-drop=ALL --pids-limit=1024 --memory=2g --cpus=1.0
|
|
run_case "3 full 去 read-only(tmpfs 保留)" \
|
|
--tmpfs /tmp:exec,size=512m,mode=1777 --shm-size=512m \
|
|
--cap-drop=ALL --security-opt=no-new-privileges --pids-limit=1024 --memory=2g --cpus=1.0
|
|
run_case "4 full 去 cap-drop=ALL" \
|
|
--read-only --tmpfs /tmp:exec,size=512m,mode=1777 --shm-size=512m \
|
|
--security-opt=no-new-privileges --pids-limit=1024 --memory=2g --cpus=1.0
|
|
run_case "5 full 去 memory/cpus 限制" \
|
|
--read-only --tmpfs /tmp:exec,size=512m,mode=1777 --shm-size=512m \
|
|
--cap-drop=ALL --security-opt=no-new-privileges --pids-limit=1024
|
|
run_case "6 full + seccomp=unconfined(只定根因,不作为修法)" "${FULL[@]}" \
|
|
--security-opt seccomp=unconfined
|
|
|
|
echo
|
|
echo "===== 判读 ====="
|
|
echo "0 FAIL => 镜像里的 chromium 150 本身跑不了,与 hardening 无关:pin 回旧版 chromium 或换 puppeteer 自带 chrome"
|
|
echo "1 PASS => docker run 层没问题,差异在 exec 路径/容器运行态:进活容器跑 probe_mermaid.sh 对比"
|
|
echo "1 FAIL, 某个 N PASS => 被去掉的那个 flag 就是根因,针对性放宽"
|
|
echo "只有 6 PASS => 宿主 docker 默认 seccomp profile 太老,不认 chromium 150 的新 syscall:升级 docker-ce 或给 sandbox 换新版 seccomp profile"
|
|
echo "全部 FAIL 含 6 => 再看内核版本(uname -r)与 chromium 150 的兼容性,考虑 pin 旧版"
|