mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-11-13 13:03:22 +09:00
323 lines
24 KiB
Markdown
323 lines
24 KiB
Markdown
# P7 wave 2-F:Ph 小件(分支 `p7/ph-f`)
|
||
|
||
> 计划见 [`PLAN-PH-P34B-P7.md`](PLAN-PH-P34B-P7.md) §1.1(PH-7、PH-8、D11、门行)与 §3 wave 2-F;
|
||
> 裁定见 [`INTEGRATOR-DECISIONS-P7.md`](INTEGRATOR-DECISIONS-P7.md) ID-P7-3(令牌足够、不做 TLS、
|
||
> `Welcome.dataNonce`);规范见 [`CONTRACT-P7.md`](../../../../MobileGL/MG_Remote/CONTRACT-P7.md) §0
|
||
> 规则 I / J、§9 簇 F、§10 第 3 条。基线 `ec46a550`。
|
||
>
|
||
> 主机口径:WSL Arch + lavapipe,`build-split` 与集成者同配置(integration tests ON)。flatc 取
|
||
> `3rdparty/flatbuffers` 子模块构建的钉版本(`scripts/gen_protocol.py`)。
|
||
>
|
||
> 基线门读数(`~/w7/logs/p7-gate-f-base.log`):G1 `.text` `0xa52203`、符号 0/0;普查 79 处 abort、
|
||
> 0 未标记;棘轮 173;车道 unit 2429 / split 303 / spawn 219 / tcp 222 / magma-tcp 74。
|
||
|
||
## 0. 每片一条提交,每片一次 red-once
|
||
|
||
下表的 SHA 都是**包树**(分支 `p7/ph-f`)上的;集成者 cherry-pick 到 `pipe` 后以那边的为准。
|
||
|
||
| 片 | 项 | 提交 | 状态 |
|
||
|---|---|---|---|
|
||
| 1 | PH-7 (1)(2)(3):常量时间令牌合一、≥16 字节(TCP 监听处)、无令牌只 loopback、smoke 入 CI | `2975a337` | 落地 |
|
||
| 2 | PH-7 (4):`Welcome.dataNonce` 把数据连接绑定到已认证的控制连接 | `596b34fd` | 落地 |
|
||
| 3 | PH-8:Hello 要 64 GiB → server 忽略请求、按自己的尺寸建段且不分配 | `a746417a` | 落地 |
|
||
| 4 | D11 五处上限 + PH-2 | — | **未做**,见 §4 |
|
||
| 5 | PH-6 drop-with-latch | — | **未做**(顺序在 4 之后) |
|
||
| 6 | PH-1 (3)(4) | — | **未做**(顺序在 4 之后) |
|
||
| F-a | 审查修复 1+4:绑定后关闭 hand-off / 单会话监听者,hand-off 发送不阻塞 | `3370833f` | 落地,见 §6.1 |
|
||
| F-b | 审查修复 2:`sha256(protocol.fbs)` 钉住 `MOBILEGL_PROTOCOL_CONTROL_REVISION` | `75f24db0` | 落地,见 §6.2 |
|
||
| F-c | 审查 nit 6/8/9/10(代码) | `2b2a0ae0` | 落地,见 §6.3 |
|
||
| F-d | 审查 nit 3/5/7/11 + 两条 §12 债(文档) | 本提交 | 落地,见 §6.4 |
|
||
|
||
red-once 原始行汇总在 `~/w7/logs/p7-ph-f-redonce.txt`。
|
||
|
||
---
|
||
|
||
## 1. 片 1:令牌策略合一(PH-7 (1)(2)(3),ID-P7-3)
|
||
|
||
### 1.1 机制
|
||
|
||
`MOBILEGL_IPC_TOKEN` 原来有三种读法:`SocketTransport.cpp` 的 `ListenTcp` 只问「非空」,所以一个字节
|
||
的令牌也能打开 `tcp://0.0.0.0`;`ServerSession::Accept` 用 `std::strcmp`;`ServerMain::RunSession` 用
|
||
`std::string::operator==`,且在 server 没配令牌时反而要求对端送空令牌。两处比较都在第一个不同字节处返回。
|
||
|
||
- 新文件 `MG_Remote/Transport/AuthToken.h`:`ConfiguredAuthToken()`(空值 = 未配置)、
|
||
`kMinimumAuthTokenBytes = 16`(**只在 TCP 监听处**问,见下条;unix 端点既不要求令牌也不问长度)、
|
||
`ConstantTimeTokenMatch`(F 修复轮起循环固定 64 字节、两端越界读零,更长的令牌比到最后一字节;长度差并入
|
||
累加器,嵌入的 NUL 参与比较)。
|
||
- `Handshake.h` `AuthenticatePeerToken`:**唯一**的策略函数,`ServerSession::Accept` 与 supervisor 子进程
|
||
(`ServerMain::RunSession`)都调它。不配置令牌时不因对端送了令牌而拒绝——策略由监听侧的 loopback 限制负责。
|
||
- `ListenTcp`:配置了但不足 16 字节的令牌**让 TCP 监听失败**(具名 `Refuse{Authentication} ... minimum is 16`,
|
||
进程退出 72),而不是悄悄退化成 loopback server。令牌值从不进日志。unix 监听者不检查这条:那条路上令牌
|
||
不是访问控制(§6.4 的本地对端债)。
|
||
- `Refuse{Authentication}` 是 `protocol.fbs` `RefuseCode` 的枚举值,`fatal_census.py` 规则 4 的词表门
|
||
直接认它;普查前后都是 3 个 refusal 词,无需新增 `.def` 行(Refuse 词不是 Fatal 家族词)。
|
||
- CI:`TcpLane.SupervisorProtocolControls` 从 wave 0 起挂在 `integration-tcp` 上却因 CI 没有 flatc 而恒为
|
||
SKIP。`test.yml` 的 integration-split 作业现在从子模块构建钉版 flatc(`gen_protocol.py --check`,
|
||
不改已提交头文件),导出 `MOBILEGL_FLATC_EXECUTABLE`,并用 `junit_tally.py --require-entry-passed
|
||
TcpLane.SupervisorProtocolControls` 断言它**跑了且过了**——SKIP 在这里等于红(`tcp_lane_tools_test.py`
|
||
覆盖 passed / skipped / notrun / failed / absent 五态)。
|
||
- smoke 新增两条监听控制:无令牌 + 通配地址 → 具名拒绝;13 字节令牌 + loopback → 具名拒绝、行里不含令牌。
|
||
|
||
### 1.2 red-once(两进程,`TcpLane.SupervisorProtocolControls`)
|
||
|
||
把 `SocketTransport.cpp` 还原到 `ec46a550`、只重链 `libMobileGL.so`:
|
||
|
||
```
|
||
RED AssertionError: (None, '... MG_Remote server: pid=42256 listening on tcp://127.0.0.1:46447')
|
||
GREEN short_token_listen exit 72: MG_Remote: Refuse{Authentication} MOBILEGL_IPC_TOKEN is 13 bytes and the
|
||
minimum is 16 (PH-7 (3)); refusing to listen on tcp://127.0.0.1:46545 rather than authenticating with
|
||
a guessable secret
|
||
```
|
||
|
||
即:改前 13 字节令牌起了一个活的监听者;改后进程以名字拒绝。单测 `SocketTransportTest.TcpRefusesToListen
|
||
WithATokenShorterThanTheMinimum` 与 `TheTokenComparisonAnswersLengthAndPrefixTheSameWay` 是廉价的那一半。
|
||
|
||
---
|
||
|
||
## 2. 片 2:`Welcome.dataNonce`(PH-7 (4),ID-P7-3)
|
||
|
||
### 2.1 现场故障
|
||
|
||
设备窗口 #1:经 Windows `adb forward` 时一个会话的两条连接**乱序**到达;`AcceptPair` 规定「先到的是控制、
|
||
后到的是数据」,于是数据连接被当成控制读 Hello,每个子进程等 10 s 后以 67 退出(日志里伴随
|
||
`only 1 of 2 connections arrived within 250 ms`)。同一条规则也意味着任何能连到端口的人都能把一条连接
|
||
插进窗口、成为别人会话的数据面。
|
||
|
||
### 2.2 机制
|
||
|
||
- `protocol.fbs`:`Welcome` 末尾追加 `dataNonce: [ubyte]`;新表 `DataBind { nonce: [ubyte]; }` 追加到
|
||
`CtrlMsg` 末尾。头文件由钉版 flatc 重新生成。
|
||
- **wire 指纹随之改变。** 原指纹的输入全是数据面的结构尺寸与编解码摘要,控制 schema 改形状不会动它。新增
|
||
`MOBILEGL_PROTOCOL_CONTROL_REVISION`(`mg_protocol_base.h`,本次 = 1)作为 `AbiFingerprintInputs.
|
||
ControlSchemaRevision` 混入;`SessionHandshakeTest.TheAbiFingerprintChangesWhenAnyOfItsInputsDoes` 钉住
|
||
该输入并加扰动行。实测 `wireFingerprint` 由 `0x7d4470f241d23539` 变为 `0x03c4c293a54b3e08`。
|
||
**设备侧后果——两个方向不对称**(审查 nit 3):
|
||
- **新 server + 旧 client**:旧 client 仍开两条连接、送旧指纹,新 supervisor 读到 Hello 后以
|
||
`Refuse{WireFingerprint}` 具名拒绝——这是有帧的那个方向。
|
||
- **旧 server + 新 client**(= 手机上的 server **没有**随本提交重装的情形):新 client 只开**一条**连接;
|
||
旧 supervisor 的 `AcceptPair` 等第二条连接 2000 ms,记 `only 1 of 2 connections arrived within ... ms`,
|
||
把两条都关掉、继续监听——**没有子进程、没有读 Hello、没有任何 `Refuse` 帧**。client 侧的症状是
|
||
`MG_Remote client: no Welcome ... (rc=6)`(`MOBILEGL_ERR_TRANSPORT_CLOSED`,对端 EOF),不是一条
|
||
具名拒绝。看到这条就先查设备上的 APK 是否是本次构建(`device-window-1-runbook.md` §2 第 3 步)。
|
||
- 指纹随 `MOBILEGL_PROTOCOL_CONTROL_REVISION` 变,而 revision 是手改的整数:F 修复轮把
|
||
`sha256(protocol.fbs)` 钉在它旁边(§6.2),改了 schema 不 bump 在单元车道与 flatc-check 里都是红。
|
||
- 流程(仅 `tcp://`;unix 端点的第二条连接是 SCM_RIGHTS 套接字,保持 `AcceptPair`——那是本地对端债,
|
||
§6.4):
|
||
1. client `SocketTransport::ConnectControl` 只连控制连接,发 Hello;
|
||
2. server 子进程在令牌通过后用内核 CSPRNG(`getrandom`,退回 `/dev/urandom`,绝不退回 PRNG)铸 128 位
|
||
nonce,`StreamLink::AttachOwnedDeferred` 先建好私有内存(Welcome 要宣告其尺寸)但**不带 fd、不起
|
||
reader 线程**,发 Welcome(带 nonce);
|
||
3. client 收到 Welcome 后 `ConnectDataConnection` 开数据连接,第一帧是 `DataBind{nonce}`,随后才挂
|
||
StreamLink;
|
||
4. supervisor 一次只 `AcceptOne`:无活会话时新连接是控制连接、fork 子进程(带一对 hand-off
|
||
socketpair);有活会话时读新连接的**恰好一帧**(`ReceiveOneFrame` 不多读一个字节——DataBind 后面
|
||
紧跟 StreamLink 自己的帧),是 DataBind 就把 fd 连同所呈 nonce(sideband)经 `FdPassing::SendFd`
|
||
交给子进程,否则照旧 `Refuse{Busy}`;
|
||
5. 子进程里 `ServerSession::BindDataConnection` 是**唯一**比较点(`ConstantTimeNonceMatch`):匹配者
|
||
`StreamLink::BindDataFd` 起 reader;不匹配者在**那条连接上**回 `Refuse{Authentication} data
|
||
connection nonce mismatch` 并关闭,等待继续——陈旧或抢插的连接结束不了它没能加入的会话。截止时间
|
||
(5 s)到则在控制连接上回 `Refuse{Authentication} no data connection presented the session nonce`;
|
||
控制对端先走则立即结束等待(子进程按 0 退出,不计入 `sessionsFaulted`)。
|
||
6. 无活会话时到达的 DataBind 由子进程具名拒绝:`Refuse{Authentication} data connection names no live
|
||
session`,干净退出 0。
|
||
- 250 ms / 2000 ms 的「两连接到达窗口」在 TCP 上不复存在;取而代之的是 nonce 匹配。非 `--serve` 的单会话
|
||
TCP 模式保留监听者,由会话自己 accept 并读 DataBind(`ListenerSource`),比较仍在同一处;F 修复轮起,
|
||
数据连接绑定后监听者随即关闭(§6.1)。
|
||
- 仍然**没有**做的:ID-P7-3 说「认证在 fork 之前完成」——本片的令牌检查与 nonce 铸造仍在 fork 出的会话子
|
||
进程里(每会话一进程,不影响绑定的正确性);把 Hello 读取与认证移进 supervisor 属于 PH-7 (5)「有界的预
|
||
认证工作 + 失败退避」,未做。
|
||
|
||
### 2.3 red-once(两进程)
|
||
|
||
探针只跑「数据连接先到、控制连接后到」这一条(新 smoke 的 (a)),server 分别是片 1 的头与本片:
|
||
|
||
```
|
||
RED (片 1 server) stray: RuntimeError: control channel closed before a complete frame
|
||
control: ConnectionResetError: [Errno 104] Connection reset by peer
|
||
supervisor: session pid=1705895 reaped exit=67 sessionsFaulted=1 ← 现场故障原样
|
||
GREEN stray: Refuse{Authentication} 'data connection names no live session'(子进程 exit=0)
|
||
control: Welcome,nonce 16 字节
|
||
```
|
||
|
||
smoke 常驻控制(`TcpLane.SupervisorProtocolControls`):`data_connection_first`(上面这条)与
|
||
`stale_nonce`(会话活着时先呈一个取反的 nonce → 那条连接收到 `Refuse{Authentication} data connection
|
||
nonce mismatch`,日志 `MGPipe: Refuse{Authentication} data connection nonce mismatch`,随后正确的 nonce
|
||
绑定、子进程打出 `ready`)。单测 `SocketTransportTest.TheDataBindIsReadExactlyAndTheStreamBehindItIsLeft
|
||
OnTheSocket` 钉住「恰好一帧」与 16 字节宽度。
|
||
|
||
`integration-tcp`(真 GL client 走新流程)222/222、`integration-magma-tcp` 74/74 保持全绿。
|
||
|
||
---
|
||
|
||
## 3. 片 3:PH-8(server 钳制尺寸)
|
||
|
||
### 3.1 机制
|
||
|
||
没有改代码:`ServerSession::Accept` 只看 Hello `linkTerms` 的 `dataPlane` / `wireForm`,段按 server 自己的
|
||
`SetSegmentSizes` 建,Welcome 宣告的也是这组。准确地说这不是「钳制」而是**忽略、按 server 尺寸**:四个计数
|
||
根本没被读去定尺寸(审查 nit 8);F 修复轮起,请求超过所授条款时 `Accept` 记一条 `MGLOG_W`(§6.3),生产
|
||
client 的 Hello 不填这四个数,所以正常会话不会打这条。本片把它钉住:
|
||
|
||
- 单测 `SessionHandshakeTest.AHelloAskingFor64GiBIsClampedToTheServersTermsAndAllocatesNothingOfIt`:
|
||
Hello 四个窗口各要 64 GiB,Welcome 必须回 server 的 4 KiB 条款,四个 SegmentRef 各 ≤ 64 KiB。
|
||
- smoke `hello_asks_64_gib`:两进程下同样的请求,Welcome 的条款 < 1 GiB,且回答它的会话子进程(Welcome
|
||
`serverPid`)在数据连接绑定后(即全部段已存在)`VmPeak` < 64 GiB。实测:maxReply 2097136、cmd 8 MiB、
|
||
stage 32 MiB、event 256 KiB,子进程 VmPeak 237264896。
|
||
|
||
### 3.2 red-once(变异:`Accept` 改为按 Hello 的条款定尺寸,已还原)
|
||
|
||
```
|
||
RED unit SessionHandshakeTest.cpp:294 Accept rc 2 != 0(64 GiB 私有段建不出来)
|
||
RED smoke hello_asks_64_gib: RuntimeError: control channel closed before a complete frame(子进程死于该请求)
|
||
GREEN 如 3.1
|
||
```
|
||
|
||
---
|
||
|
||
## 4. 片 4–6 未做,以及为什么停在这里
|
||
|
||
计划的停止规则:「某片超过一天就停在上一片」。片 4(D11 五处 + PH-2)的代码改动本身不大,但每一处都要求
|
||
**一条在两进程臂上、字节来自对端的负控**,而树上没有任何车道能把一条**越过 client 自身守卫**的畸形记录
|
||
送进一个 spawn / TCP server:
|
||
|
||
- `create_render_state` 的 `Cso.Slot`、`read_pixels` 的 `W×H`(client 在发射前按回复槽尺寸自检)、程序归档
|
||
里的 `ArchiveVector` 计数、`StagedTextureStore` 的 run 与 level extent、`SlotTables` 的 handle slot/gen——
|
||
全都由 client 的编码器生成且被它自己的检查挡住;要到达 server 必须有一个能按需伪造记录的对端(fuzz 臂 2
|
||
「超界计数」一行正是这件事,计划里记在 P7 之后)。
|
||
- 另外两处落在簇 F 之外、且会碰 pull 构建:`ProgramArtifactsCodec.cpp` 编进 pull 构建(G1 `.text` 要求新界限
|
||
只能在 `MOBILEGL_BUILD_DISAGGREGATED` 内),`SlotTables.h` 在簇 D 的 `MG_Backend/DirectGLES/` 下,且
|
||
`MGPipeFatalFamily` 目前只有 `UnmigratedVerb` / `RoleViolation`,PH-2 的具名拒绝需要先加一个
|
||
`ProtocolCorruption` 族并在 hook 映射里接上。
|
||
- 已核实的一点备查:`MG_Pipe/PipeApply.cpp` **不在** pull 构建里(`build-linux/compile_commands.json`
|
||
无该文件),D11 第一行在那里改不影响 G1。
|
||
|
||
所以片 4 连同其后的片 5(PH-6)、片 6(PH-1 (3)(4))按规则未开工。建议下一包先落「对端伪造记录」的两进程
|
||
驱动(它同时是 fuzz 臂 2 的骨架),再逐处上界限,每处一条经它红一次的负控。
|
||
|
||
---
|
||
|
||
## 5. 门(片 1–3 的头 `a746417a`,包树 SHA;F 修复轮的头见 §7)
|
||
|
||
| 门 | 基线 `ec46a550` | 头 |
|
||
|---|---|---|
|
||
| G1 pull `.text` / 符号增删 | `0xa52203` / 0/0 | `0xa52203` / 0/0(`build-linux` 无需重编:簇 F 文件不在 pull 构建) |
|
||
| `fatal_census.py` | 79 abort、44 家族词、3 refusal 词、0 未标记 | 同左 |
|
||
| `link_ratchet.py --assert-monotone` | 173 | 173(不变) |
|
||
| `spawn_lane_parity.py` | 0 错 | 0 错 |
|
||
| unit | 2429 | 2433(+4:片 1 两条、片 2 一条、片 3 一条) |
|
||
| integration-split | 303 | 303 |
|
||
| integration-spawn | 219 | 219 |
|
||
| integration-tcp | 222 | 222 |
|
||
| integration-magma-tcp | 74 | 74 |
|
||
|
||
---
|
||
|
||
## 6. F 修复轮:片 1–3 的 fable 审查(裁定 land with fixes)
|
||
|
||
审查的 11 条里 should-fix 五条(1–5)、nit 六条(6–11);下面按提交分。每条都有一次 red-once,原始行在
|
||
`~/w7/logs/p7-ph-f-redonce.txt` 的 `F fix round` 段。
|
||
|
||
### 6.1 修复 1 + 4(`3370833f`):绑定之后,数据连接的来源随即关闭
|
||
|
||
**缺陷 1(回归)。** 子进程只在 `BindDataConnection` 里读 hand-off socketpair,数据连接绑定后再也不读;而
|
||
supervisor 的 `RouteWhileBusy` 对此后**每一条** DataBind 仍然 `SendFd` 进去。后果:每个 fd 在子进程的接收
|
||
队列里躺着、对端**没有任何回复**(不是具名拒绝;改前基线对第二条连接还会回 `Refuse{Busy}`),那条 TCP 连接一直
|
||
挂到会话结束;队列到 `net.unix.max_dgram_qlen`(手机内核默认 10;本机 512,但发送端 sndbuf 在 ~288 个
|
||
datagram 处先满)后 supervisor **阻塞在 `sendmsg`** 直到会话结束——不再 accept、不再回 Busy、不再 reap。
|
||
|
||
**缺陷 4。** 非 `--serve` 的单会话 TCP 模式为 `ListenerSource` 留着监听者,数据连接绑定后没人关它:内核继续
|
||
完成三次握手进 backlog,第二个 client / 重试要等满 `kSpawnConnectTimeoutMs`(20 s)而不是像改前那样立即
|
||
`ECONNREFUSED`。
|
||
|
||
**修法(同一个钩子)。** `RunSession` 多收一个 `sourceFd`——`--serve` 下是子进程那端 `pair[1]`,单会话下是
|
||
监听者——`session.Accept()` 一返回就 `close` 并清掉 `DataConnectionSource`。于是 (1) supervisor 再转发时
|
||
`sendmsg` 得到 `ECONNREFUSED`/`ENOTCONN`(`FdPassing::SendFd` 把「对端已走」当答案而不是错误日志),已有的
|
||
`Refuse{Authentication} data connection could not be handed to the live session` 按名字打出;`SendFd` 加
|
||
`dontWait`(`MSG_DONTWAIT`),队列因别的原因满也拒绝而不是卡住;(4) 单会话的第二个连接立即 `ECONNREFUSED`。
|
||
|
||
**red-once**(server 还原到 `da313010`,只重建 `.so`):
|
||
|
||
```
|
||
RED smoke data_bind_after_bound: TimeoutError: timed out(第一条多余 DataBind 的 receive 就超时——没人回)
|
||
RED probe f1probe.py(qlen+2 条 DataBind 只发不收): extras opened=288 of 514 后 connect/send 超时;
|
||
answered by name=0 silent=288;此后新开控制连接: CONNECT FAILED TimeoutError(supervisor 卡在 sendmsg);
|
||
supervisor alive=True
|
||
RED smoke single_session_listener: 绑定后的第二个 connect 成功(监听者还开着)
|
||
GREEN smoke data_bind_after_bound: refused=12,每条 Refuse{Authentication} 'data connection could not be
|
||
handed to the live session';随后新开控制连接 → Refuse{Busy}
|
||
GREEN probe: 514/514 具名拒绝、silent=0、新控制连接 → Busy、supervisor alive
|
||
GREEN smoke single_session_listener: second_connect=ConnectionRefusedError(111)
|
||
```
|
||
|
||
smoke 常驻控制两条:`data_bind_after_bound`(会话 `ready` 后 12 条多余 DataBind 各得具名拒绝、再开控制连接仍
|
||
Busy)与 `single_session_listener`(无 `--serve` 的 supervisor,`ready` 后 connect 必须 `ECONNREFUSED`)。
|
||
`held_session` / `pair` 共用 `connect_control`(启动期 `ECONNREFUSED` 重试 5 s)。
|
||
|
||
### 6.2 修复 2(`75f24db0`):`sha256(protocol.fbs)` 钉住 revision
|
||
|
||
revision 是手改整数,改了 `protocol.fbs` 不 bump 就回到「新旧对端指纹相同、字段静默缺失」。
|
||
`scripts/ci/protocol_revision_pin.py` 持有表 `{revision → sha256(protocol.fbs)}`
|
||
(`protocol_revision_pins.json`,行尾折成 LF 再哈希),当前 revision 没有行、或行与文件摘要不符都红;`--write`
|
||
在 bump 后记新行,且拒绝把已有 revision 改钉到另一个摘要(那正是「改 schema 没 bump」的样子)。注册为
|
||
`ProtocolSchema.RevisionPinsDigest`(label unit,`--self-test` 先证明两种扰动都红才说绿),并作为 CI
|
||
`flatc-check` 作业的一步——正是每次 schema 改动都要重新生成头文件的那个作业。
|
||
|
||
```
|
||
RED protocol.fbs 末尾加一行注释、revision 仍为 1:
|
||
::error::protocol.fbs has sha256 a7b5c7fb888d2926... but MOBILEGL_PROTOCOL_CONTROL_REVISION is still 1,
|
||
which is pinned to 7fc859f7fa756818... rc=1
|
||
GREEN 还原: protocol revision pin: revision 1 holds (sha256 7fc859f7fa756818..., 1 revision(s) pinned,
|
||
self-test red on both perturbations) rc=0
|
||
```
|
||
|
||
### 6.3 nit 6 / 8 / 9 / 10(`2b2a0ae0`)
|
||
|
||
- **nit 6** `AuthToken.h`:改前循环长度 = 本端令牌长度,响应时间正比于**秘密**的长度而头注释写得像什么都不泄。
|
||
现在循环固定 `kAuthTokenCompareBytes = 64`(更长的令牌延到其长度,只泄露「长于 64」),两端越界读零、长度差
|
||
仍并入累加器、不延到对端长度(不让对端选我们的工作量)。`SocketTransportTest.TheTokenComparisonAnswersLength
|
||
AndPrefixTheSameWay` 加 70 字节令牌最后一字节判定的用例。
|
||
- **nit 8** `ServerSession::Accept`:请求超过所授条款 → 一条 `MGLOG_W`:`Hello asked for windows the server
|
||
does not grant (cmd=68719476736 ...); the ask is ignored and the session is server-sized (cmd=8388608
|
||
stage=33554432 event=262144 maxReply=2097136) - PH-8`。单测 §3.1 那条现在要求这一行(改前红:行不存在)。
|
||
- **nit 9** `ServerSession::Accept`:`MintNonce` 失败先在控制连接上回 `Refuse{LinkTerms} stream data plane
|
||
unavailable: the server could not mint a data nonce`,再返回原错误(仍是 67、仍计入 `sessionsFaulted`——
|
||
CSPRNG 给不出字节是 server 的故障不是对端的条款)。没有驱动:不注入故障造不出 `getrandom` + `/dev/urandom`
|
||
同时失败,记录于此。
|
||
- **nit 10** `RouteWhileBusy`:有活会话时首帧 magic 错或超 1 MiB(`ReceiveOneFrame` 回 `PROTOCOL_MISMATCH`)
|
||
改回 `Refuse{MalformedHello} first frame is not a control frame`(`Accept` 对不可验证 Hello 用的同一个词),
|
||
关闭前先把对端已发的字节读掉免得 RST 冲掉拒绝帧;格式正确但不是 DataBind 的帧仍是 Busy。smoke 常驻控制
|
||
`garbage_first_frame_while_busy`(magic `XXXX` → code 8;改前红:code 7)。普查仍 3 个 refusal 词(新拒绝
|
||
走枚举值,源码里没有新字面量)。
|
||
|
||
### 6.4 记录债(本轮补记;CONTRACT-P7 §12 同步)
|
||
|
||
- **unix 端点仍按到达顺序配对**(`AcceptPair` 的 250 ms / 2000 ms 窗口)。`SocketTransport.h` 把它写成
|
||
「同用户 rendezvous、别人够不着」——但抽象命名空间套接字**没有 mode bits**,「只有本 app 能连」这条性质靠的是
|
||
Android 的 SELinux 域隔离,不是传输层自己。本地对端债,不在 Ph 的远端威胁模型里,未做。
|
||
- **两处 wave 2-F 之前就存在的预认证暴露**(审查核实、归 PH-7 (5)):(a) supervisor 对每条 TCP 连接**先 fork
|
||
再读 Hello**,未认证对端每连接可让 server 付出一次 fork + 最长 10 s 的 Hello 等待;(b) `ValidatePeerHandshake`
|
||
在 `AuthenticatePeerToken` **之前**跑,`Refuse{ProtocolVersion|WireFingerprint|BuildFingerprint}` 把本端
|
||
wire 指纹与 build stamp 送给了未认证的对端。**(P7 F2 包 f2-auth 已关 (a)(b)**:supervisor 在 fork 前自己读首帧、
|
||
先验令牌,待认证工作有期限、有上限、按地址公平让位,失败按地址退避;unix 端点的「先 fork 再读 Hello」仍在,
|
||
归本地对端债。旋钮与留下的债见 CONTRACT-P7 §12 末条、`MG_Remote/Server/PreAuthGate.h`。**)**
|
||
- 令牌最小长度只在 TCP 监听处检查(§1.1)。
|
||
|
||
---
|
||
|
||
## 7. 门(F 修复轮的头 `2b2a0ae0`,包树 SHA;F-d 只改文档,二进制同此头)
|
||
|
||
读数 `~/w7/logs/p7-ph-f-fgate.log`、车道日志 `~/w7/logs/p7-ph-f-ffinal-*.log`。
|
||
|
||
| 门 | 片 1–3 头 `a746417a` | F 修复轮头 |
|
||
|---|---|---|
|
||
| G1 pull `.text` / 符号增删 | `0xa52203` / 0/0 | `0xa52203` / 0/0(`build-linux` 无工作;`compile_commands.json` 里 `MG_Remote` 条目 0——簇 F 文件不在 pull 构建,`mg_protocol_base.h` 只改注释) |
|
||
| `fatal_census.py` | 79 abort、44 家族词、3 refusal 词、0 未标记 | 同左(新拒绝走枚举值,无新字面量) |
|
||
| `link_ratchet.py --assert-monotone` | 173 | 173 |
|
||
| `spawn_lane_parity.py` | 0 错 | rc 0(split 193 / spawn 190 / tcp 190) |
|
||
| `protocol_revision_pin.py --self-test` | — | revision 1 holds,两种扰动均红 |
|
||
| G14 名集合 | — | 对 `~/w7/p7-before` 基线 removed=1(`CapsMirrorTest.APlaceholderMirrorConsumesNothing`,在本包基线 `da313010` 上已不存在,是更早的 P7 波次退的)、added=2819;本轮只增 `ProtocolSchema.RevisionPinsDigest` |
|
||
| unit | 2433 | 2434(+1:`ProtocolSchema.RevisionPinsDigest`;`SessionHandshakeTest` / `SocketTransportTest` 的新断言在既有用例内) |
|
||
| integration-tcp | 222 | 222(`TcpLane.SupervisorProtocolControls` Passed,evidence 17 项含 `data_bind_after_bound` / `garbage_first_frame_while_busy` / `single_session_listener`) |
|
||
| integration-spawn | 219 | 219 |
|
||
| integration-magma-tcp | 74 | 74 |
|