# 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//home/sessions/----/session-/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 -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 官方源,经用户授权)—— 用于解压会话记录。