Files
dsh_ai1net_server/dsh-server-docs/04-调整方案/32-mcntimo会话取证与沙箱P0核查.md
T
admin 5ad755116e chore(docs): 文档库并入代码仓(R4 选 a)+ 索引/台账跟进
1) dsh-server-docs/ 从工作区(原 E:\...\aliyun-dsh-server\dsh-server-docs)**整体并入本仓**,
   保留目录名 ⇒ 仓库内 dsh-server-docs/... 的相对引用天然继续有效;旧目录(含其 .git)已归档到
   工作区 _中间产物_待清理/,未随本提交带入。
2) .gitattributes:新增 `dsh-server-docs/** -text` —— 原文档库是 `* -text` + autocrlf=false,
   必须保持纯 LF,否则会被本仓的 CRLF 规则翻掉。
3) 活引用里的绝对路径已全部改到新位置(docs 的 INDEX / README / scripts / skills + 用户级 skills
   + ~/.workbuddy/settings.json 的 hooks);历史档案(04-调整方案/、archive/)按「只增不改」未动。
   ⚠️ hooks 路径改动需「完全重启会话」才生效(配置是会话启动快照)。
4) 交接单/T08:新增 §16「生产整体切换执行记录」(形态 / 落地动作 / **4 个只有真上线才暴露的真 bug** /
   验收证据 / 回滚命令 / 残留项);台账 T08 行 → 已完成并归档;03-路线图 §二 登记 T08 收尾项。
5) 统一称谓:**「本机」只指跑 WorkBuddy 的开发机**,47 / 106 一律写「远程服务器」。
2026-09-15 18:47:13 +08:00

78 lines
6.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
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.
# 32 · mcntimo 会话取证与「dsh 沙箱不可用」P0 核查
- 日期:2026-09-11
- 触发:用户要求「看 admin 在 mcntimo 工作空间下的对话记录,能发现哪些问题」
- 状态:**🔍 核查完成,P0 待决策(未修复)**
> **TL;DR**|**结论**:admin 在 mcntimo 工作区的会话取证 → 查出 **「dsh 沙箱不可用 → 拒绝执行任何 shell」** 这一 P0。
> **关键**:取证方法可复用(会话事件流 → 错误归类 → 根因);该 P0 由档案 23/33 处置。
> **状态**:🔍 核查完成(P0 当时待决策)
## 一、取证方法(可复用)
- 会话文件:`/var/lib/dshs/users/<UID>/home/sessions/--<cwd 路径把斜杠换成横杠>--/session-<uuid>/session.jsonl.zstd`
- 工作区注册表:`$DSH_HOME/storages/workspace.json`(id → path/title/sessionIds)
- **坑**:文件是**追加式多帧 zstd**。Node 内置 `zstdDecompressSync` / `createZstdDecompress` 只能解**第一帧**(得 240 字节 session 头,随后报 `Unknown frame descriptor`)→ **必须用 zstd CLI**(服务器原先未装,已 `yum install -y zstd` 装上 `zstd-1.5.1-2.0.2.al8`)。
- mcntimo 共 2 个会话:主会话 **2268 行 / 1.61 MB**;另一会话 4 行(空会话)。
## 二、P0:dsh 的 `workspace-write` 沙箱在平台环境下不可用 → 拒绝执行任何 shell
**现象**:实例里执行 shell 报
```
sandbox mode "workspace-write" is requested but no sandbox backend is usable on this host;
refusing to run the command unconfined. ... otherwise switch the consumer to danger-full-access.
```
出自 `@deepseek-ai/dsh-sandbox/lib/index.js:185`。**fail-closed:没有可用后端就拒绝执行**,不是降级。
**独立核实**(非仅凭日志):
| 项 | 实测值 | 结论 |
|---|---|---|
| 内核 | `5.10.134-19.1.al8.x86_64` | **Landlock 需 5.13+ → 不可用** |
| LSM | `/sys/kernel/security/lsm` = `capability,selinux` | **landlock 未启用** |
| `/sys/kernel/security/landlock` | 不存在 | 同上 |
| bubblewrap | 0.4.0 已装 | 但 dsh 的后端探测仍判为不可用 |
| 平台合成根 /bin /sbin /lib 符号链接 | **在位**(档案 23 的修复) | 该修复未解决本问题 |
| 实例内直接跑命令 | `nsenter -t <pid> -m -p ... /bin/sh -c "id"` → **成功**(uid=114801) | 平台层没坏,坏的是 **dsh 内部沙箱探测** |
| 实例命名空间内跑嵌套 bwrap | 失败(execvp 阶段) | 与「后端不可用」一致;**未复现**日志里的 `Can't mount proc: Operation not permitted` |
**会话证据(行号分布)**:沙箱报错出现在第 **44 / 113-121 / 156 / 174 / 180 / 614-619 / 658 / 805-809 / 908 / 1060-1065** 行 —— **分布全篇**;而**末 400 行报错数 = 0**,因为用户中途手动把权限切到 `danger-full-access`。
→ 定性:**默认模式坏、切了就好**的模式性问题,不是一次性故障。
**影响面(判断)**:
1. **新会话 / 新用户开箱即用不了 shell**(默认 `workspace-write`)—— 最严重:普通用户第一件想做的事就撞墙。
2. 报错文案是写给开发者的(「Install bubblewrap or run a Landlock-enforcing kernel…」),**普通用户看不懂**;且把「切 danger-full-access」这条降级路径直接写在报错里 —— **等于引导用户主动关掉沙箱**。
3. 用户为此**连点三次要求「突破限制」**(见下),产品侧无阻断、无上报。
**未做(待决策)**:仍需在**新会话(默认 workspace-write)**里实测一次 shell,确认 P0 是否仍存活。若存活,候选方向:
- **A(推荐)**:平台层已提供 bwrap + uid + cgroup 隔离,dsh 自己的沙箱属**冗余**且有副作用 → 把 dsh 沙箱默认设为 `danger-full-access`,并在实例 UI/文档说明「隔离由平台层负责」。需同步评估语义(用户会看到「完全权限」字样)。
- **B**:让 dsh 的 bwrap 后端在嵌套环境下可用(需 platform bwrap 放开 `--unshare-user` 等,风险与工作量都更高)。
- **C**:保持现状 + 只做报错文案的产品化提示(治标)。
## 三、其他发现(P1/P2)
| 级别 | 问题 | 证据 |
|---|---|---|
| P1 | 权限预设「每会话」、UI 不可持久化,新会话回落 `workspace-write`;报错却让用户去找 consumer 切换 | 会话内助手原话「默认仍是 workspace-write,预设是每会话的」 |
| P1 | **摘护栏只需一次点击**:`ask → never` + `danger-full-access`,**无二次确认、无风险提示** | 会话出现 `approval policy changed from "ask" to "never"` |
| P1 | **工作区是空目录**(`ws/mcntimo` 只有 `.`/`..`),建会话无校验、无提示 | `ls .` 输出 `total 8` |
| P2 | 用户**3 次**要求「突破沙箱限制」,产品侧无阻断/无审计上报 | 会话原文「可以试试看能否突破限制」「现在已开启完全权限,是否可以突破限制」 |
| P2 | 工具报错噪音大、常指向不存在路径,浪费轮次 | `rg: /opt/dshs: No such file`、`rg: /var/log: No such file` |
**凭据扫描**:**0 命中**(无 sk- / bearer / JWT / AKIA / 私钥)。
**异常中断**:未发现(6 轮 turn/end 全 completed;53 次工具调用,其中 7 次 bash 有 2 次被沙箱拒)。
## 四、附:同一批并行的另一条只读通道(dsh-market 安全审计)
结论摘要(尚未单独成档):`dsh-market` **不能装任意来源,但能自助安装官方目录全部 3408 款插件、零审批**,且**「配置备份恢复」路径可绕过目录校验直接装任意 GitHub 源** → **对「admin 投放 → 用户启用」第三层管控构成实质绕过**(风险等级:中;实例隔离兜住爆炸半径,越不到宿主/其他租户/平台 DB)。
证据:`routes.ts:4193` 安装前只校验「是否在社区目录里」;`registry.ts:169 loadRegistry()` 每次实时抓官方 `plugins.json`,无本地白名单;`backup.ts:139 validatedBackup` 只校验格式、不校验依赖 spec。
## 五、本次附带的环境变更
- 服务器安装 `zstd-1.5.1-2.0.2.al8`(yum 官方源,经用户授权)—— 用于解压会话记录。