新增Trap23:上传中止后首笔复连上传被静默截断(2048B)并误报成功,可信复现15/15,N-8待修

This commit is contained in:
2026-09-23 01:10:37 +08:00
parent 0e6efb44a3
commit 5a41b966fc
2 changed files with 39 additions and 0 deletions
+38
View File
@@ -635,3 +635,41 @@ CH395F 片内 TCP 状态机的角(芯片固件,MCU 侧无法修补)。2026
### 发现时间
2026-09-22(Trap 21 二次 2×2 复核台架副产品,A 组 run2)。
## Trap 23:上传中止后首笔复连上传被静默截断(≤2048B)并误报成功
### 现象
客户端上传(STOR)中途断开(用户取消 / 网络断;**RST 或优雅 FIN 均可**),**紧随其后的第一笔复连上传被截断到 ≤2048 字节(= 芯片单 socket RX 缓冲大小),且服务端回报 226 上传成功** → 客户端(ftplib 等)据此认为上传成功 = **静默数据损坏**;第二笔及以后恢复正常。
### 证据(可信复现:生产固件、零固件探针;工具 `MDK-ARM/ftp_abort_probe.py`)
- 判据 = FTP 协议结果 + **紧接一笔正常上传的 SHA-256 往返校验(STOR→RETR 比对)** + 控制通道 NOOP 存活探测;
- **RST 中止:10/10 复现**首笔复连上传截断(请求 4096B → 设备日志 `UPLOAD '/ab_ok.bin' 2048 bytes OK`);
- **优雅 FIN 中止:5/5 同样复现** → 与 RST/FIN 无关,凡"数据未发完即断开"均触发;
- 中止那一笔自身也被记为 `UPLOAD ... 2048 bytes OK` + 226(FTP 无长度声明,语义边界;但客户端会误判成功);
- **对照(无中止)**:177 轮(8KB/64KB/256KB/1MB,含 100 轮零间隔浸泡)全部 SHA-256 匹配(`MDK-ARM/ftp_freeze_probe.py`),并发 UI 流 600 帧 CRC 全过 → 中止路径是唯一触发条件。
### 机制(设备侧日志实证)
1. 中止时数据 socket 被释放(RST 时芯片上报 `sock4 TIMEOUT`),net 层随即 `auto-relisten ok` + `relisten retry ok`(**监听端口复用**);
2. 下一笔连接:`sock4 standalone accept` → `CMD STOR` → **紧接着一条陈旧 `sock4 DISCONNECTED, releasing (chip tcp=0x00)`**(旧连接收尾状态落在新连接上);
3. lftpd 数据读循环据此读到 EOF → 把已到的 2048B 当作整个文件 → `UPLOAD ... 2048 bytes OK` + 226;
4. 再下一笔连接时芯片状态已干净 → 正常(故为"一次性"而非持久故障)。
### 影响
- **静默数据损坏**:上传被中断后"重试的第一笔"会生成截断文件且客户端收到成功回报(FTP 客户端通常不做长度校验)→ 现场可能表现为"上传的文件损坏/不完整";
- 主风险面 = 生产路径 STOR(上传);RETR(下载)不涉及;
- 与 TC-NET-604 的关系:本条为**独立、已复现**的真实缺陷;TC-NET-604 的台架"冻结"结论已撤回(见 Trap 21 顶部更正块),现场"卡死/失败"报告应优先用本条的判据(协议结果 + 哈希往返)复核。
### 复现
```
& '.venv\Scripts\python.exe' MDK-ARM\ftp_abort_probe.py --rounds 10 --send 8192 --gap 1
& '.venv\Scripts\python.exe' MDK-ARM\ftp_abort_probe.py --rounds 5 --send 8192 --gap 1 --graceful
```
### 修复方向(待办 N-8)
1. **relisten 前让芯片 socket 真正沉降**:确认 `ch395f_get_socket_status == CLOSED` 且清掉该 socket 中断状态后再 listen(现有 relisten 的单次清理在中止场景下不足);
2. **新连接的陈旧中断防御**:数据 socket 刚 accept、尚未读到任何数据就收到 DISCONNECT 时判为陈旧中断 → 重新 relisten,而不是当作正常 EOF 结束上传;
3. **应用侧兜底**:`receive_file` 区分"正常 EOF"与"连接异常结束",异常时回 5xx(让客户端重试)而非 226,避免误报成功;
4. **回归判据**:`ftp_abort_probe.py` 的 `followup` 由 FAIL → **OK(10/10)**,且 `ftp_freeze_probe.py` 的 177 轮对照仍全匹配。
### 发现时间
2026-09-23(可信复现首轮:真实生产路径 FTP 中止/复连场景,由 `MDK-ARM/ftp_abort_probe.py` 自动判定)