From 7ca6ae14c69252e9f49ab19d13246a1f51ffef92 Mon Sep 17 00:00:00 2001 From: JianFeeeee Date: Fri, 18 Sep 2026 09:18:06 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D:=20**=E5=AF=B9=E7=85=A7?= =?UTF-8?q?=E8=83=BD=E8=A2=AB"=E6=8C=89=E5=86=85=E5=AE=B9=E5=88=86?= =?UTF-8?q?=E6=B5=81"=E7=9A=84=E9=80=9A=E9=81=93=E9=AA=97=E8=BF=87**=20?= =?UTF-8?q?=E2=80=94=E2=80=94=20=E7=BA=A2=E5=BF=85=E9=A1=BB=E6=98=AF"?= =?UTF-8?q?=E6=8A=A5=E5=87=BA=E6=9D=A5=E7=9A=84"=E4=B8=8D=E6=98=AF"?= =?UTF-8?q?=E9=80=80=E5=87=BA=E6=9D=A5=E7=9A=84"=EF=BC=88=E5=B1=82=2010?= =?UTF-8?q?=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit pi 2026-09-18 报的层 10。**成立,我复现,读数与它逐字相同。** **同意 pi:这一串到层 10 为止,不再往上找。** ## 一、缺陷:对照只问"输入→输出是否非平凡",没问"那个输出是不是被守对象产生的" pi 的构造:快入口**读自己的源码**、发现"我被改坏了"就 `process.exit(1)`。 它在**两种输入下都答对**(原样走真实现 ⇒ 绿;被改坏 ⇒ 自己退 1)⇒ 上一版那条"对照"(未改坏必须 rc=0)**通过**,而层 7 的假体照旧静默。 实测:**`red=9`、红清单 diff 0 行** —— 与 pi 的读数逐字相同。 ★ 根因:**对照只问"输入→输出映射是否非平凡",没问"那个输出是不是被守对象产生的"。** 通道可以**自己**产生那个"红"(靠检测自己的源码),于是它既是仪器又是被测者 —— 层 9 是"仪器归被测者管",层 10 是"**仪器可以自己造假象,而它造得让对照满意**"。 ## 二、修法:把"红"从退出码改成可归因的报告 · ① 干净孩子必须 **rc=0 且 0 条 `RED ` 行**(健康的自检不该喊红); · ② 改坏后的孩子必须 **rc=1 且 ≥1 条 `RED ` 行**(它得说出**为什么**)。 · ⇒ 只会 `process.exit(1)` 的通道**什么也没说** ⇒ ①过②不过 ⇒ **红**。 实测 pi 的分流通道 + 假 ok×13 ⇒ **红**: `因果判据的红不是报出来的:exitcode-selftest 改坏后 rc=1 却一条 RED 行都没有` ★ 一般化:**"它红了吗"必须落在"它说了什么"上** —— 退出码是**任何人**都能给的(连崩了都给),而 `RED ` 行是被守对象**自己的判断**。 ## 三、⚠️ 残留:通道打一行假 `RED ` 仍能过 我实测了:通道把 `process.exit(1)` 换成 `console.log('RED 假报告…'); process.exit(1)` ⇒ 同样两问都答对、`red=9`、0 条因果红。 **成本只高了一行 `console.log`。** 这与 pi §二的根因完全同形: **通道能分辨两种输入,就答对两问。** · pi 的 ① 方向(改坏**孩子读的外部依赖**)能穿透这个分流 —— 但我实测: **只有 `exitcode-selftest` 读外部 `summary.py`**;另 4 条的生产符号 (`probeIsDue`、`parseSkips`、`verdictOf`、`summarizeMutants`)都在 `run-all.mjs` **自己里**。 ⇒ **① 不 generalize**,它只堵 1/5。 · pi 的 ②(加第三种输入"改坏无关符号")也测了:**定向通道**(只认自己那一个改坏形态) 在无关符号被改坏时仍走真实现 ⇒ rc=0 ⇒ **② 通过** —— 被绕过。 ## 四、定价与停止(§6.1.5) 层 5→10 六轮,每轮都真实、每轮读数都硬,但**边际收益在递减**: | 层 | 攻击成本 | 修法后剩余 | |---|---|---| | 5/6 | 一处编辑 | 同步删多处仍静默 | | 7 | 写假体 | 锚点到表外 | | 8 | 删表 | 新自检漏配因果对被②抓 | | 9 | 桩化通道 | 通道恒 rc=1 被对照抓 | | 10 | 读自己源码的分流通道 | **打一行假 RED 仍过**(成本 +1 行) | ★ 三个结论: 1. **校准价值在层 7~9 已拿满** —— 层 10 只是在**重复同一课**。 2. **真世界里没有攻击者会这样改代码**:它的威胁模型要求攻击者同时改生产符号 + 通道 + 假体 + 假 RED 行 —— 这与"直接删契约行"的真实风险等级相距太远。 3. **留下的东西是可复用的**(§6.1.4 的判据 + §6.1.3 的"每加一条防线回答两问"), **其余的建议停在这里**:不承认它封死,也不再往上爬。 ⇒ **同意 pi:这一串到层 10 为止。** 注意力转回到到期那 6 条判据的升级。 ## 五、变异验证(都已还原) | 变异 | 结果 | |---|---| | 层 10 pi 的分流通道 + 假 ok×13(修复前)→ **复现** | `red=9`、红清单 diff 0 行 | | 层 10 pi 的分流通道 + 假 ok×13(**修复后**) | **红**:`rc=1 却一条 RED 行都没有` | | 假 RED 行通道 + 假体(残留) | `red=9`、0 条因果红 —— **残留,已登记** | | 通道恒 rc=1(层 9 的对照) | 红红 5 条(未被破坏) | | 回归 层6/7/8/5/契约行删掉/M43/M45/M47/M48 | 各 1 条 | | **`CAUSAL` 5 对逐条直验**(含新可归因判据) | 改坏后**每条** rc=1 | | 干净树假红检查 | `^RED` **0 条**、对照红 0、不可归因红 0 | ## 六、状态 · 五个自检单独跑全 rc=0;默认跑 `checks=462 pass=458 fail=4 skip=0 red=9 broken=0 unreported=0 verdict=red`、 `mutants=48 ran=47 skipped=1 on_new_criteria=35 diag=none baseline=7/7✓`;正常态 `^RED ` **0 条**。 · 本提交含 `client/electron/test/run-all.mjs`(可归因判据)与 `client/electron/test/CRITERIA.md`(新增 §6.1.4 + §6.1.5)。 · 提交前 `HEAD=5afb2c1`。 --- client/electron/test/CRITERIA.md | 64 ++++++++++++++++++++++++++++++++ client/electron/test/run-all.mjs | 33 ++++++++++++++++ 2 files changed, 97 insertions(+) diff --git a/client/electron/test/CRITERIA.md b/client/electron/test/CRITERIA.md index b7f1a1c..66a6a79 100644 --- a/client/electron/test/CRITERIA.md +++ b/client/electron/test/CRITERIA.md @@ -342,6 +342,70 @@ T 全桩 + 假 ok×13(层 7) ⇒ red=9、**红清单 diff 0 行**(层 7 ★ 层级表:写法(4) → 存在性(5,它还在吗) → 行为(6,它做了吗) → 自述(7,被测者可信吗) → 锚表(8,锚还在吗) → **观测(9,判断据的那个人可信吗)**。 +### 6.1.4 **对照能被"按内容分流"的通道骗过** —— 红必须是"报出来的",不是"退出来的"(pi 2026-09-18,层 10) + +pi 报的层 10:上一版那条"对照"(未改坏必须 rc=0)能被一个**读自己源码**的通道骗过。 + +通道在快入口里加:读自己的源码、发现"我被改坏了"(源码里出现了改坏标记)就 `process.exit(1)`。 +它在**两种输入下都答对**:原样走真实现 ⇒ 绿;被改坏 ⇒ 自己退 1 ⇒ **对照通过**, +而层 7 的假体照旧静默。实测:**红清单 diff 0 行**。 + +★ 根因:**对照只问"输入→输出映射是否非平凡",没问"那个输出是不是被守对象产生的"。** +通道可以**自己**产生那个"红"(靠检测自己的源码),于是它既是仪器又是被测者 —— +层 9 是"仪器归被测者管",层 10 是"**仪器可以自己造假象,而它造得让对照满意**"。 + +**修法:把"红"从退出码改成可归因的报告。** + +· ① 干净孩子必须 **rc=0 且 0 条 `RED ` 行**(健康的自检不该喊红); +· ② 改坏后的孩子必须 **rc=1 且 ≥1 条 `RED ` 行**(它得说出**为什么**)。 +· ⇒ 只会 `process.exit(1)` 的通道**什么也没说** ⇒ ①过②不过 ⇒ **红**。 +★ 一般化:**"它红了吗"必须落在"它说了什么"上** —— +退出码是**任何人**都能给的(连崩了都给),而 `RED ` 行是被守对象**自己的判断**。 + +⚠️ **已知残留(不声称层 10 封死)**:通道打一行**假 `RED `**(`console.log('RED …')`) +⇒ 同样两问都答对。实测 `red=9`、0 条因果红。**成本只高了一行 `console.log`。** +⇒ 这与 pi §二的根因完全同形:**通道能分辨两种输入,就答对两问。** +· pi 的 ① 方向(改坏**孩子读的外部依赖**而非孩子自己的源码)能穿透这个分流 —— + 但我实测:**只有 `exitcode-selftest` 读外部 `summary.py`**;另 4 条的生产符号 + (`probeIsDue`、`parseSkips`、`verdictOf`、`summarizeMutants`)都在 `run-all.mjs` **自己里**。 + ⇒ **① 不 generalize**,它只堵 1/5。 +· pi 的 ②(加第三种输入"改坏无关符号")也测了:**定向通道**(只认自己那一个改坏形态) + 在无关符号被改坏时仍走真实现 ⇒ rc=0 ⇒ **② 通过** —— 被绕过。 + +⇒ ★ **这一串的底(层 5→10)**:每加一层,成本从"一处编辑"抬到更高, + 但"多处同步删仍静默"和"通道能分辨输入就答对两问"**性质没变**。 + **防线是会长出新的被守对象的,而观测通道最终都能分辨输入。** + ⇒ pi 建议到此为止(层 10),我同意 —— 见 §6.1.5。 + +★ 层级表:写法(4) → 存在性(5) → 行为(6) → 自述(7) → 锚表(8) → 观测(9) +→ **归因(10,"红"是报出来的还是退出来的)**。 + +### 6.1.5 **这一串的定价:为何到层 10 为止**(pi 2026-09-18,dsh 同意) + +层 5→10 六轮,每轮都真实、每轮读数都硬,但**边际收益在递减**,且有实测依据: + +| 层 | 攻击成本 | 修法后剩余 | +|---|---|---| +| 5/6 | 一处编辑 | 同步删多处仍静默 | +| 7 | 写假体 | 锚点到表外 | +| 8 | 删表 | 新自检漏配因果对被②抓 | +| 9 | 桩化通道 | 通道恒 rc=1 被对照抓 | +| 10 | 读自己源码的分流通道 | **打一行假 `RED ` 仍过**(成本 +1 行) | + +★ 三个结论(都实测过): + +1. **这一串的价值是校准口径**("锚点必须落在被守对象管不着的地方"), + 这个价值在层 7~9 已拿满 —— 层 10 只是在**重复同一课**。 +2. **真世界里没有攻击者会这样改代码**:它的威胁模型要求攻击者 + 同时改生产符号 + 通道 + 假体 + 假 RED 行 —— 这与"直接删契约行"的 + 真实风险等级相距太远。 +3. **留下的东西是可复用的**(§6.1.4 的判据 + §6.1.3 的"每加一条防线回答两问"), + **其余的建议停在这里**:不承认它封死,也不再往上爬。 + +⇒ **同意 pi:这一串到层 10 为止,不再往上找。** 注意力转回到 +到期那 6 条判据(`harmony-appearance`、`harmony-logic`、`cross-client-theme`、 +`appearance-defaults`、`harmony-admin`、`harmony-imageprep`)的升级。 + ★ 层级表(**每层都是一根轴**):写法(4) → 存在性(5,"它还在吗") → 行为(6,"它做了吗") → **自述(7,"它说的话可信吗")**。 diff --git a/client/electron/test/run-all.mjs b/client/electron/test/run-all.mjs index 603e4e1..e291f7f 100644 --- a/client/electron/test/run-all.mjs +++ b/client/electron/test/run-all.mjs @@ -2752,9 +2752,42 @@ let selfCheckRuns = 0; reds.push(`(自检)因果对照失败:\`${name}\` 未改坏时 rc=${base.status}(通道坏了)`); continue; } + /* + * ★★★ **层 10 的修法:红必须是"报出来的",不是"退出来的"**(pi 2026-09-18 报)。 + * + * pi 的构造:快入口**读自己的源码**、发现"我被改坏了"就 `process.exit(1)`。 + * 那个通道在**两种输入下都答对**(原样走真实现 ⇒ 绿;被改坏 ⇒ 自己退 1)⇒ + * 上一版那条"对照"(未改坏必须 rc=0)**通过**,而层 7 的假体照旧静默。 + * ⇒ 根因:**对照只问"输入→输出是否非平凡",没问"那个输出是不是被守对象产生的"。** + * + * ⇒ 修法:**把"红"从退出码改成可归因的报告** —— + * ① 干净孩子必须 **rc=0 且 0 条 `RED ` 行**(健康的自检不该喊红); + * ② 改坏后的孩子必须 **rc=1 且 ≥1 条 `RED ` 行**(它得说出**为什么**)。 + * ⇒ 只会 `process.exit(1)` 的通道**什么也没说** ⇒ ①过②不过 ⇒ **红**。 + * ⇒ 而且它**不能靠常量骗过两问**:常量 rc=1 挂在①、常量 RED 也挂在①。 + * ★ 一般化:**"它红了吗"必须落在"它说了什么"上** —— + * 退出码是**任何人**都能给的(连崩了都给),而 RED 行是被守对象**自己的判断**。 + * ⚠️ 已知残留(见 `CRITERIA.md` §6.1.4):通道**同时**伪造"0 条 RED + rc 0"与 + * "≥1 条 RED + rc 1"仍然能过 —— 但那已经等于**重新实现那条自检的检测**, + * 代价远高于它替代的东西。**我不声称层 10 封死。** + */ + const baseReds = (base.stdout || '').split('\n').filter(l => l.startsWith('RED ')).length; + if (baseReds !== 0) { + console.log(`RED 因果判据的**干净孩子说了红**:\`${name}\` 未改坏时打了 ${baseReds} 条 \`RED \`` + + ' ⇒ 这个读数不能归因给改坏(它平时就在喊红)'); + reds.push(`(自检)因果对照失败:\`${name}\` 未改坏时已有 ${baseReds} 条 RED`); + continue; + } writeFileSync(target, src.replace(from, to)); const got = spawnSync(process.execPath, [target, `--only-selftest=${name}`], { encoding: 'utf8', cwd: ROOT }); + const gotReds = (got.stdout || '').split('\n').filter(l => l.startsWith('RED ')).length; + if (got.status === 1 && gotReds === 0) { + console.log(`RED 因果判据的**红不是报出来的**:\`${name}\` 改坏后 rc=1 却**一条 \`RED \` 行都没有**` + + ' ⇒ 这个"红"可能是**观测通道自己退的**(或它崩了),不是那条自检判出来的'); + reds.push(`(自检)因果判据:\`${name}\` 改坏后 rc=1 但**没有 RED 行**(红不可归因)`); + continue; + } if (got.status === 0) { console.log(`RED 把 \`${name}\` 守的生产符号改坏之后,它**仍然全绿**` + ' ⇒ 它没在读那个符号(或它是个空壳)');