Files
codex-app-server/docs/chv-muse-p5-gap.md
T
host 25bcd355f8 feat(chv): 对齐 Muse P5 纵深——eBPF 污点传播 + 五档严格能力 + 对话外审批 + 默认策略
- taint.py:污点追踪器(登记/污点不可逆/子进程继承/审计)
- ebpf_taint.py:eBPF 程序源码 + 加载器(能力探测 + 降级);
  本机实测加载被 seccomp 挡(bpf() EPERM),报 blocked 不冒充
- capabilities.py:五档严格能力(一次/会话/任务/时限/永久,
  三元组绑定 + 精确匹配 + 撤销;permanent 默认不签发)
- policy.py:默认策略规则表 + 谨慎度三档(写操作与敏感路径
  永远不自动放行,规则变化审计)
- approval_channel.py:对话外审批通道(nonce + 15 分钟过期 +
  HMAC,答复一次有效,对话伪造无效)
- sentinel.py 接线:evaluate() 可选接 taint/policy/tier/scope,
  不传时行为与 P3 一致;自动放行步骤 + 档位签发回落单次;
  Capability 基类属性放宽为 Optional(None = 不限)
- 新测试 61 项;全量 cloud 套件 1958 项 OK(skipped=8)

真机待验证(未做,排队在 round-11 之后):见
docs/chv-muse-p5-gap.md §4
2026-11-06 22:25:55 +00:00

72 lines
13 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.
# 对齐 Muse P5 差距表:Sentinel 纵深(eBPF 污点传播 + 严格能力完整化 + 对话外审批 + 默认策略)
依据:`~/workspace/research_notes/meta-muse-ai-architecture-20261101-0755/report.md`
(官方以 Meta security.muse.ai 2026-09-08 为准;第三方拆解只作参考,
逆向细节不得写成官方架构)。Muse 官方 Sentinel 要求:Sentinel 是
连接器动作与全部网络出口的唯一权限机构;网络出口审批在 L4 与 L7
评估主机名、解析后与最终目的 IP、端口、协议、HTTP 方法、路径、
解码后的实际请求,并有 SSRF 防护;污点出口——每个工具执行进程
初始干净,读取用户数据后变“污点”,干净且符合窄范围自动放行策略
并通过出站 URL 其他检查的请求可免打扰放行,污点或不可验证进程
失去自动放行、回到正常审批流,实现用 eBPF cgroup 程序做网络拦截
与进程归因、及挂在 LSM hook 上的 eBPF 程序做污点传播;审批是
严格能力,绑定到特定连接器/目的地与用例,支持一次性、会话级、
任务级、时限级、永久级授权,Sentinel 决定向用户呈现哪几种授权
类型,并确保后续调用与授权范围精确匹配;审批 UI 不在对话内,
Sentinel 直接向客户端发审批请求、用户答复直接回 Sentinel;默认
策略只读/先前已允许/明显低风险动作可不打扰通过。
本轨范围只限 P5:Sentinel 纵深。起点是 P3(分支 feat-chv-muse-p3
提交 a90cf78,已合入本分支,见下文“起点”)。不碰 P1(常驻 VM、
气球、vsock)、不碰 P2(nspawn 单元、浏览器)、不碰 P4(浏览器
完全对齐)、不碰 P6(privsep worker)。分支 `feat-chv-muse-p5`
(从 `feat-chv-cover100` 分出,基线 HEAD `06c3e17`)。
## 0. 起点(P3 已做的,本轨不重写)
P3 交付的 `cloud/chv/sentinel.py`(决策层,纯函数 + 内存态队列,
标准库):`SentinelPolicy.evaluate()`(allow/deny/ask;L4 解析后
IP/端口/协议 + L7 主机/方法/路径;SSRF 挡截;未知连接器/scheme/
端口/路径越界 → deny;不在白名单 → ask);严格能力 `Capability`
(绑定 {连接器, 主机, 方法, 路径, 有效期, 次数},默认单次 + 300 秒
TTL,`matches()`/`use()`);`ApprovalQueue`(ask 记入内存态待审批,
resolve 只标记不放行)。两个接线点:wake 时 Gitea 出口预审、
authd 放凭证前评估。P3 明确列为后续的本轨三项:eBPF 污点传播、
审批 UI 不在对话内(只留队列)、能力只有一次性一档(官方有五档)。
## 1. 现状 vs Muse
| 项 | 现状(实测/代码为准) | Muse 目标 | 本轨做法 |
|---|---|---|---|
| 污点出口 | 无。Sentinel 是决策层,不拦截客内流量;客内直连靠 Tinyproxy 白名单 + 宿主防火墙兜底;进程“读了用户数据”这个事实没有任何地方记录 | 每个工具执行进程初始干净,读用户数据后变污点;干净 + 窄范围自动放行策略 + 出站 URL 检查通过 → 免打扰放行;污点或不可验证进程失去自动放行、回正常审批流;eBPF cgroup 程序做网络拦截与进程归因、LSM hook 做污点传播 | `cloud/chv/taint.py`(污点追踪器:进程干净/污点两态、读用户数据事件 → 污点、子进程继承、审计)+ `cloud/chv/ebpf_taint.py`(eBPF 程序源码 + 加载器 + 能力探测 + 降级);宿主侧先做可测试的最小闭环:策略引擎(纯标准库、可单测)+ eBPF 加载层(可探测、失败时明确降级、不冒充已加载)。客内 eBPF 加载可行性实测后写进 §3,不行就写清阻塞点 |
| 严格能力分级 | 只有一档:单次 + 300 秒 TTL(P3 默认)。无会话/任务/时限/永久的概念;无“用例”维度(只绑连接器/主机/方法/路径) | 严格能力绑定到特定连接器/目的地与用例,支持一次性、会话级、任务级、时限级、永久级授权;Sentinel 决定向用户呈现哪几种授权类型;后续调用与授权范围精确匹配 | `cloud/chv/capabilities.py`:五档全实现(one-shot / session / task / timed / permanent),能力绑定 {连接器, 目的地, 用例} 三元组 + 方法/路径/次数/过期;`matches()` 精确匹配检查(超范围即 deny + 审计);每档的签发条件与上限写进规则表(永久级默认不签发,须显式策略开启 + 审计) |
| 审批 UI 在对话外 | 只有 `ApprovalQueue` 内存态队列:ask 记入、resolve 只标记;没有任何请求/答复通道;对话内容伪造审批的风险只在文档里写了约束,无机制防 | Sentinel 直接向客户端发审批请求,弹窗在客户端 UI 内,答复直接回 Sentinel;目的:防对话内容伪造审批 | `cloud/chv/approval_channel.py`:独立审批通道(请求/答复协议、nonce + 有效期 + 签名/HMAC 校验,答复须与请求绑定;对话内容里出现的“批准”字样一律无效);通道两端接口 + 契约文档;客户端 UI 呈现是另一侧的事,留好接口、不冒充已做 UI |
| 默认策略 | 只有 default-deny + 白名单/拒绝名单 + L7 规则;无“只读/已允许/低风险不打扰”的分层规则,无可调谨慎度 | 只读、先前已允许、明显低风险动作可不打扰通过;用户可把默认调得更谨慎或更宽松 | `cloud/chv/policy.py`:默认策略规则表(只读方法 GET/HEAD + 已允许主机/路径 + 低风险判定)+ 谨慎度三档(default / cautious / permissive,默认 default;permissive 不放行写操作与敏感路径);规则变化(档位切换、规则增删)全部审计 |
| 审计 | P3 的 `_emit` 契约:`sentinel_egress_allow/deny/ask`,detail 只含连接器/主机/路径/verdict/原因,不含凭证值 | 审计轨迹展示已做与计划做的事 | 沿用契约,新增事件:`sentinel_taint_marked`(进程变污点)、`sentinel_auto_allow`(干净进程自动放行)、`sentinel_capability_denied`(超范围/过期/超次)、`sentinel_approval_requested/answered`(通道审批)、`sentinel_policy_changed`(规则/档位变化);detail 只含进程/连接器/目标/ verdict/原因,绝不含用户数据内容与凭证值 |
## 2. 改了什么(本轨交付物,已做完)
- `cloud/chv/taint.py`(新,标准库):污点追踪器——进程注册(pid/cgroup/连接器/用例)、干净 → 污点(`mark_tainted(pid, source)`,source 只存分类)、子进程继承污点、污点不可清除(无任何清除入口,只随进程退出消失)、`is_tainted`、`auto_allow_eligible`(污点与未知 pid 一律 False)、审计(事件名 + pid + 原因,无内容、无凭证值)。
- `cloud/chv/ebpf_taint.py`(新,标准库):eBPF 程序源码常量(`cgroup_skb/egress` 拦截 + `taint_map` HASH 进程归因 map + RINGBUF 事件上报;`lsm/file_open` 污点传播骨架,共用 pin 住的 map,路径表由用户态下发、不读文件内容)+ `EbpfTaintLoader`(能力探测:内核版本、/sys/fs/bpf 是否存在可写、CapEff bit 39 CAP_BPF / bit 21 CAP_SYS_ADMIN、bpftool/clang/llvm-objdump;状态 loaded/degraded/blocked + 原因;加载失败一律降级为 `policy_engine_proxy_hooks`,`try_load` 须 bpftool 加载 + pin 在位双重确认才报 loaded)。
- `cloud/chv/capabilities.py`(新,标准库):五档严格能力,继承 P3 `Capability`——one-shot(单次/300 秒)、session(会话 id 绑定,默认 3600 秒)、task(任务 id 绑定,默认 3600 秒)、timed(须显式 ttl)、permanent(默认拒绝,须显式 `allow_permanent=True`);绑定 {连接器, 主机, 用例} 三元组 + 方法/路径/次数/过期;`matches(request, now, scope)` 精确匹配(`scope` 须按关键字传,`now` 仍占第二位置参数,与 P3 旧口径一致);`use()`/`revoke()`;签发/使用/过期/超次/撤销全审计。
- `cloud/chv/policy.py`(新,标准库):默认策略规则表 + 谨慎度三档(default:已允许主机 + 路径前缀;cautious:精确主机 + 精确路径;permissive:只读 + 非敏感即候选,不必先前已允许);三档共性:写操作与敏感路径(/admin、/settings、/login、token 相关)永远不自动放行,污点进程一律不自动放行;`set_caution`/`add_rule`/`remove_rule` 每次变化记 `sentinel_policy_changed` 审计。
- `cloud/chv/approval_channel.py`(新,标准库):独立审批通道——`ApprovalRequest.payload()`(pending_id + nonce + 目标描述 + 原因 + 过期,默认 15 分钟,无凭证值与用户数据内容);`Answer`(pending_id + nonce + verdict + 过期 + HMAC-SHA256 签名);`verify_answer`(pending 存在 + nonce 对上 + 未过期 + 签名对上 + verdict 合法,五项缺一即 False);`resolve_via_channel`(校验通过才调 `ApprovalQueue.resolve`,成功即消费登记、答复只能用一次);密钥由调用方保管,通道不保存密钥、不进载荷、不进日志。
- 接线(`cloud/chv/sentinel.py`,唯一改动的已有文件):`evaluate()` 新增可选接线参数(`taint_tracker`/`pid`/`default_policy`/`tier`/`scope`),不传时行为与 P3 完全一致;安全检查(步骤 1–6)抽成 `_safety_verdict`;新增自动放行步骤(干净进程 + 只读 + 已允许 + 低风险 + 过 L7 路径规则 → allow + 按档位签发能力,原因 `policy_auto_allow`;污点进程一律不放行、回到正常审批流);档位签发失败回落单次(更严格,原因 `capability_tier_fallback`,不抛错);`Decision` 加 `tainted` 标记(审计里仅当 True 时出现);`Capability` 基类的 `max_uses`/`uses_left`/`expires_at` 放宽为 Optional(None = 不限,供五档用;单次档仍是 int,行为不变)。
- `cloud/tests/test_chv_muse_p5_taint.py`(18 项)、`test_chv_muse_p5_capabilities.py`(21 项)、`test_chv_muse_p5_approval.py`(11 项)、`test_chv_muse_p5_wiring.py`(11 项,接线:自动放行/污点回流/三档策略/档位签发与回落/通道端到端/对话伪造无效)。新测试共 61 项。
## 3. 诚实边界(本轮不宣称的东西)
1. **eBPF 加载在本机实测不行,证据确凿(不是推断)**:本 Muse VM 实测(2026-11-07,ctypes 直接调 `bpf()`,syscall 号 321):最小合法程序 `BPF_PROG_LOAD`(SOCKET_FILTER,`r0=0; exit`,GPL)返回 **-1,errno 1 EPERM,verifier 日志为空**;`BPF_MAP_CREATE` 同样 -1 EPERM。空 verifier 日志说明在 verifier 之前就被挡;`/proc/self/status` 显示 `Seccomp: 2`(filter 模式)——**`bpf()` 系统调用本身被 seccomp 挡,能力位在位不等于系统调用放行**。其余探测:内核 7.0.0-43-generic;CapEff `000001fffff7cfff` 解码 CAP_BPF bit 39 = 在位、CAP_SYS_ADMIN bit 21 = 在位;`/usr/include/linux/bpf.h` 在位,gcc 在位;但**无 `/sys/fs/bpf`**(`/sys/fs` 下 0 处 bpf 挂载)、**无 bpftool/clang/llvm-objdump**。加载器 `probe()` 因此报 `blocked`(blockers 含 `bpffs_missing`、`tool_missing:bpftool/clang/llvm-objdump`)。本轨交付“策略引擎 + 加载器 + 降级”与本实测结论,不把“写了 eBPF 程序源码”等同于“eBPF 已在拦截流量”。客内(WSL 测试机 VM 里)加载可行性须真机验证,见 §4;教训:真机验证须先确认客内容器/VM 的 seccomp 配置是否放行 `bpf()`,只看 CapEff 会误判。
2. **污点追踪的“读用户数据”事件靠调用方上报**:纯用户态追踪器不知道进程真读了什么文件——污点标记的输入是工具执行层在读用户数据前调用 `mark_tainted()`(或 LSM hook 回调,eBPF 通了才有真事件)。没接 LSM hook 之前,漏报是可能的;本轨不宣称“所有读用户数据的行为都被捕获”。
3. **审批通道不是客户端 UI**:本轨做请求/答复协议与校验,不做弹窗 UI。没有客户端接入之前,ask 仍须人工在通道外处理;不得写成“审批弹窗已上线”。
4. **永久级能力默认不签发**:按 Muse 口径 Sentinel 决定呈现哪几种授权类型;本轨永久级默认关闭,须显式策略开启 + 审计;开启后仍绑定三元组与审计,永不过期不等于无审计。
5. **无真机验证**:本轮全部是代码 + 本地单测。真机待验证清单见 §4,测试机须排队(第三棒 V-1~V-9 与 round-11 之后)。
## 4. 真机待验证清单(测试机空闲后,round-11 之后排队)
1. eBPF 程序在 WSL 测试机客内真加载:加载是否成功、cgroup 拦截是否真拦住直连、进程归因 map 是否对得上 pid、LSM hook 是否真收到读事件。
2. 污点进程在真机上的出口表现:干净进程自动放行、读用户数据后出口回审批流、ask 停止执行。
3. 五档能力在真机 wake/同步路径下的表现:会话/任务级能力跨多次调用仍有效、过期/超次即拒。
4. 审批通道端到端:ask 发出 → 通道外答复 → 放行/拒绝生效;对话内容伪造答复在真机上无效。
5. 默认策略三档在真机上的表现:cautious 档是否多拦、permissive 档是否仍挡写操作与敏感路径。