From 662dcccbf2a0abb63e57bf1a75dc5245b0c72106 Mon Sep 17 00:00:00 2001 From: cbb <2625274797@qq.com> Date: Tue, 20 Oct 2026 21:12:10 +0800 Subject: [PATCH] =?UTF-8?q?docs(review):=20=E4=B8=93=E5=AE=B6=E8=AF=84?= =?UTF-8?q?=E5=AE=A1=202026-10-19?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/audit_ecat_spi_wifi_ota_compatibility.md | 2 + ...pi_wifi_ota_compatibility.rev2026-10-19.md | 34 ++++++++ docs/compose/spec/REVIEW_STATUS_2026-10-19.md | 18 ++++ docs/review/DCU_APP_专家评审_2026-10-19.html | 86 +++++++++++++++++++ 4 files changed, 140 insertions(+) create mode 100644 docs/audit_ecat_spi_wifi_ota_compatibility.rev2026-10-19.md create mode 100644 docs/compose/spec/REVIEW_STATUS_2026-10-19.md create mode 100644 docs/review/DCU_APP_专家评审_2026-10-19.html diff --git a/docs/audit_ecat_spi_wifi_ota_compatibility.md b/docs/audit_ecat_spi_wifi_ota_compatibility.md index 4ebccd9..8b99635 100644 --- a/docs/audit_ecat_spi_wifi_ota_compatibility.md +++ b/docs/audit_ecat_spi_wifi_ota_compatibility.md @@ -1,3 +1,5 @@ +> **2026-10-19 复核说明**:本报告的结论已于 2026-10-19 对 master@d8b3c97 逐条复核,多数补丁未合入、“全部闭环”结论不成立。最新状态见 [修订跟踪](audit_ecat_spi_wifi_ota_compatibility.rev2026-10-19.md) 与 [专家评审](review/DCU_APP_专家评审_2026-10-19.html)。以下为原文,未改动。 + # GD32E508 DCU 固件多总线并发兼容性、本地 OTA 隔离关停与电机中继 OTA 排他性系统级安全审计报告与防御加固方案 - **文档标识**:`DCU-AUDIT-ECAT-SPI-WIFI-OTA-20260918` diff --git a/docs/audit_ecat_spi_wifi_ota_compatibility.rev2026-10-19.md b/docs/audit_ecat_spi_wifi_ota_compatibility.rev2026-10-19.md new file mode 100644 index 0000000..6e7059b --- /dev/null +++ b/docs/audit_ecat_spi_wifi_ota_compatibility.rev2026-10-19.md @@ -0,0 +1,34 @@ +# 修订跟踪:audit_ecat_spi_wifi_ota_compatibility.md(2026-10-19 复核) + +- 原文件:`docs/audit_ecat_spi_wifi_ota_compatibility.md`(v2.0,2026-09-18),保留不改正文。 +- 复核基线:master @ d8b3c97(APP 1.7.4)。完整评审见 `docs/review/DCU_APP_专家评审_2026-10-19.html`。 +- 总体结论:原报告“98.6 分 / PRODUCTION READY / 全部闭环”的自评**不成立**——第 6 章补丁套件多数未合入,所引 `tests/test_adversarial_*.py` 在仓库中不存在。 + +| 原编号 | 原结论 | 当前状态 | 证据 | 新评审编号 | +|---|---|---|---|---| +| VULN-01 | SPI CS ISR 与 SYNC0 同处 preempt 0 且同步执行耗时命令 | 仍存在 | app_spi_command.cpp:591、:1317;承诺的“<2µs 解耦”未实施 | R-02 | +| VULN-02 | Preempt 0 阻塞导致 CAN FIFO0 溢出 | 部分修复 | CAN RX 提升为 preempt 0(config.h:373),FIFO 改为丢新不覆旧(CANFD.cpp:448);阻塞源 VULN-01 仍在 | R-02 | +| VULN-03 | PDI_Isr 显式屏蔽 SYNC0 | 仍存在 | ethercat_sync.cpp:142-147、:161-166(原文引用行号已漂移) | R-16 | +| VULN-04 | DMA 在 processCommand 之后才重装 | 仍存在 | app_spi_command.cpp:1317→1320 | R-17 | +| VULN-05 | 按铃事件被查询帧抹除 | 仍存在(影响面缩小) | app_spi_command.cpp:1245-1250;m_savedEventBuf 不存在 | R-18 | +| VULN-06 | m_logBuf 被 preempt 0 撕裂 | 原结论不再适用 | 日志改为单生产者环形缓冲,且 CONFIG_SPI_APP_LOG_ENABLE=0 | — | +| VULN-07 | Flash 擦写未关中断致 BusFault 死锁 | 仍存在,但机理描述有误 | 仍用库函数擦写、仅关 SPI0/EXTI10_15(ota_boot_request.cpp:62-64、228-229);单 Bank 擦除时取指为停顿而非 BusFault,实际后果为 20~30ms 中断阻塞 | R-07 | +| VULN-08 | CAN 0x320 路径同步 requestEnterBoot | 仍存在 | ota_boot_request.cpp:199-213 | R-07 | +| VULN-09 | 复位前无外设优雅关停 | 仍存在 | ota_boot_request.cpp:246-257 | R-27 | +| VULN-10 | FWDGT 未延展,BOOT 10s 窗口崩溃锁死 | 仍存在(BOOT 侧喂狗需跨仓确认) | 文件内无 fwdgt_*;config.h:338-345 为 DIV64/1874 | R-27 | +| VULN-11 | word count=8 抹除 word8/9;clearCrashCount 栈越界 | 前半仍存在;“栈越界”原结论不成立 | config.h:359=8;clearCrashCount 走 writeWord 路径(ota_boot_request.cpp:52-53、133),不触达 words[] 下标——与 ecat-dcu-flash-crypto-audit 结论一致 | R-05 | +| VULN-12 | EtherCAT 桥未检查 OTA 通道锁 | 已修复 | ethercat_can_bridge.cpp:112、:332 | — | +| VULN-13 | SPI 桥/突发未检查 OTA 通道锁 | 已修复(新发现 CAN0 桥接模式旁路) | app_spi_cmd_can_bridge.cpp:83;app_spi_cmd_can_burst.cpp:85;旁路见 R-11 | R-11 | +| VULN-14 | start() 加锁前存在漏包窗口 | 部分修复 | motor_ota_relay.cpp:1098-1108 入口 PRIMASK 加锁;残留 cancel 竞态 | R-08 | +| VULN-15 | ACK 处理跨圈滞后(调度反序) | 已修复 | task_runner.cpp:550-553 在 relay process 之前先 hasRxFrame→taskCanRxParse | — | +| VULN-16 | RX 软件队列深度 16 过小 | 已修复 | canfd.h:277 深度改为 64 | — | +| 审计总评 | 自评“98.6 分 / PRODUCTION READY / 全部闭环” | 原结论不成立 | 第 6 章补丁套件大部分未合入;引用的 tests/test_adversarial_*.py 在仓库中不存在 | — | + +## 原报告中的事实性勘误 +- §2.1 优先级表多数源码行号已漂移:EXTI10_15 优先级在 `app_spi_command.cpp:591`,SPI0_IRQn 在 `:533`,`CONFIG_NVIC_PRIORITY_GROUP` 在 `config.h:365`;EXTI10_15 与 CAN RX 均为 preempt 0 的描述正确。 +- §3.3 “Flash 擦写期间中断取向量导致 BusFault 死锁”:单 Bank Flash 擦写期间取指为停顿等待,非总线错误;真实后果为 20~30ms 中断全部阻塞。 +- §3.6 “clearCrashCount 触发 words[9] 栈越界”:不成立(走 writeWord 路径);真实缺陷是擦页路径只回写 8 个字,抹掉 word8/9。 +- 0xA2 在 ISR 内忙等:实测代码为两段各最多 200×50µs,最长约 20ms(原文写 10ms)。 + +## 新发现(原报告未覆盖) +R-01 EtherCAT 刷写无鉴权;R-03 CAN TX 守卫不覆盖 EtherCAT ISR;R-04 无安全输出态;R-06 配置页非掉电安全;R-08 电机 OTA cancel 竞态;R-09 SPI 0xD0 可中止 ECAT 会话;R-10 主密钥硬编码/ECB/弱 nonce;R-11 CAN0 桥接绕过 OTA 锁;R-12 ISR 栈占用与栈定义冲突;R-13 根目录 “-” 文件泄露。详见 HTML 评审。 diff --git a/docs/compose/spec/REVIEW_STATUS_2026-10-19.md b/docs/compose/spec/REVIEW_STATUS_2026-10-19.md new file mode 100644 index 0000000..e7f8fc2 --- /dev/null +++ b/docs/compose/spec/REVIEW_STATUS_2026-10-19.md @@ -0,0 +1,18 @@ +# 既有设计/审计记录状态复核(2026-10-19) + +基线:master @ d8b3c97。原文件均保留未改。完整评审见 `docs/review/DCU_APP_专家评审_2026-10-19.html`。 + +| 记录 | 原结论/内容 | 当前状态 | +|---|---|---| +| `docs/compose/spec/ecat-dcu-flash-crypto-audit.md` | DCU 刷写无载荷加密;word count=8;CAN 路径同步;无 teardown/fwdgt;BOOT 侧不可验证 | 仍成立;补充:BOOT 侧经跨仓核实 arm 门可被 0x2502 无鉴权打开(R-01) | +| `docs/compose/spec/lan9252-perf-audit.md` | P1 差分写 ESC、P2 csrRead verify 分级 | 已实现:config.h:134 SPARSE=1、:143 DIFF=1;esc_lan9252.h:84 csrRead(verify)。上机对拍仍待做;front-matter updated 日期与提交时间不符 | +| `docs/compose/spec/ecat-wkc-periodic-dip.md` | 主因 B:输出侧每 256 拍强制全量读 | 机制仍存在(ethercat_pdo.cpp:114-134),未见修复提交;仍待现场 A/B 对拍 | +| `docs/compose/spec/tiered-pdo-mapping.md` | status: designed,按电机数分档收缩 SM3 | 未实现:全仓无 tier 相关代码,SM3 仍为 600B | +| `docs/compose/spec/warm-jump-ecat-probe.md` | 起板探针改为 BYTE_TEST 放行 | 已实现并保留(esc_lan9252.cpp 使用 LAN9252_BYTE_TEST_VALUE) | +| `.trae/specs/fix-ethercat-realtime-comm-risks` | s_periodicSeq、safe* 接口、PDO 三缓冲 | 被后续 SSC 集成取代:periodicIsr/三缓冲桥已删除,PDO 由 SSC 3-buffer SM 完成 | +| `.trae/specs/fix-ecat-postaudit-risks` | H1 safe* 收窄;M1 SYNC0 RAM 化;M2 NVIC 分组前移;M3 删 readBlock | H1/M3 已落地(safe*、readBlock 均已不存在);M1 已落地(ethercat_sync.cpp:112、:188 .ramfunc);M2 已落地(initial.cpp:222) | +| `.trae/specs/fix-ecat-pdo-and-runtime-issues` | S1 PDI 偏移分离、S2 process 桥、S3 AL 守卫、M4-M7 | S1/S2 被 SSC 架构取代;S3 部分保留(ethercat_slave.h:32 getAlState);M4-M7 随旧路径删除 | +| `.trae/documents/cleanup-residual-low-risk-optimizations.md` | 13 项低风险清理 | 抽查均已落地:canfd_diag_t、m_ringTxLen、s_pushCount 已删除,sys/hardfault.h 已删除,spinDelay/armRingPending 已提取,ADC 匿名 namespace 已合并 | +| `README.md` | 工程结构说明 | 大面积过时(见 R-40) | + +备注:lan9252-perf-audit 的 front-matter `updated: 2026-02-14` 与实际提交日期(2026-09-12)不符;ecat-wkc-periodic-dip 标注“本文件不提交”但已在仓库中。 diff --git a/docs/review/DCU_APP_专家评审_2026-10-19.html b/docs/review/DCU_APP_专家评审_2026-10-19.html new file mode 100644 index 0000000..103286c --- /dev/null +++ b/docs/review/DCU_APP_专家评审_2026-10-19.html @@ -0,0 +1,86 @@ + +DCU_APP 专家评审 2026-10-19
+

GD32E508 DCU_APP 固件专家评审

+

仓库:cbb/DCU_APP(master @ d8b3c97,2026-10-11,APP 版本 1.7.4) 评审日期:2026-10-19 产出方式:多专家视角静态评审(未上板、未交叉编译)

+
1致命
12严重
28一般
6建议
48 / 100综合评分
+ +

1. 项目概述与架构

+

DCU(GD32E508VE,Cortex-M33@180MHz,512KB Flash/128KB SRAM)是机器人整机的通信网关:EtherCAT 从站(LAN9252 经 EXMC 16 位 HBI,Beckhoff SSC 协议栈)、SPI0 从机连接 ESP32(WiFi/上位机)、3 路 CAN-FD 连接关节电机,并承担 DCU 本地 OTA 交接与电机固件中继 OTA。

+
+ EtherCAT 主站 ──100BASE-TX──▶ LAN9252 ESC ══EXMC HBI══╗
+ Web/上位机 ──WiFi──▶ ESP32 ──SPI0 从机(PA15 CS / PB6 READY)══╣
+ 关节电机 ×N ◀──CAN-FD ×3 (CAN0/1/2, STB 脚)────────────────╣
+                                                          ▼
+ ┌──────────────── GD32E508 DCU_APP ────────────────┐
+ │ ISR: EXTI0 SYNC0(p0) │ EXTI10_15 SPI CS(p0) │ CAN RX(p0)│
+ │      EXTI1 PDI/ESC IRQ(p1) │ EXTI2 SYNC1(p1) │ TIMER2(p1)│
+ │      CAN TX / SPI0 ERR(p2) │ USART0(p3) │ SysTick(p15)    │
+ │ 主循环 TaskRunner: 喂狗 → SPI poll → CAN RX 解析 →      │
+ │   EcatMotorOta/MotorOtaRelay → SSC MainLoop → 周期任务  │
+ │ Flash: BOOT 0x0800_0000 │ 备份 APP │ 主 APP 0x0804_8000 │
+ │        OTA 配置页 0x0807_E000 (word0..9, shared/ota_layout.h)│
+ └──────────────────────────────────────────────────┘
+
+ + + + + + +
目录职责规模/要点
sys/初始化、调度、OTA 交接、电机 OTA 中继、AES、临界区、HardFaultmotor_ota_relay.cpp 1284 行;config.h 集中配置
device/CAN-FD、ADC、USART、Timer、看门狗、电机状态/版本CANFD.cpp 2026 行(最大文件)
device/spi/ESP32 SPI Link v2 命令总线与各命令处理器app_spi_command.cpp 1375 行;协议核心 spi_link_v2 在仓库外
comm/LAN9252/EXMC 驱动、SYNC、PDO、CAN 桥、电机 OTA 邮箱进料esc_lan9252.cpp 718 行,关键路径 .ramfunc
comm/ssc/Beckhoff SSC 协议栈 + 本地移植层(dc_app.c、ESI、EEPROM 生成)ecatslv.c 2512 行;PDO 输出 384B / 输入 600B,ESI/EEPROM/代码一致
RTE/GigaDevice 厂商库、启动文件、链接脚本链接脚本含 .ramfunc 执行区;栈/堆定义三套并存
+ +

2. 评审范围与方法

+ +

安全提示:仓库根目录文件 “-” 含电机 OTA 主密钥常量。本报告只描述该风险,不转载任何密钥值。

+ +

3. 问题清单

+
编号严重度领域文件:行号现象风险修改建议
R-01致命OTA/安全comm/ssc/port/dc_app.c:330-351;跨仓 GD32E50X_BOOT sys/OTA.cpp:848-866、:960SDO 0x2502 写 1 即触发回 BOOT 并把 EN 置 NOT_AVAL;BOOT 的 ecatArmed() 仅凭 CHECK/EN 不同时为 AVAL 即放行;之后 ecatFeed/ecatCommit 写入明文,CRC 由设备对自己写入的内容计算,不与发送方提供值比对任何能接入 EtherCAT 网段的主站都可无鉴权把任意固件刷入 DCU(含恶意或错误镜像),整机失控/变砖引入镜像签名(ECDSA/Ed25519)或至少 HMAC,BOOT 在 commit 前验签;0x2502 增加挑战-应答令牌并要求 AL≤PREOP、电机未运行
R-02严重实时/SPIdevice/spi/app_spi_command.cpp:591、:1317;comm/esc_lan9252.cpp:366-383EXTI10_15(SPI CS)配置为 preempt 0,与 SYNC0、CAN RX 同级;ESP32 全部命令在该 ISR 内同步执行,0xA2 唤醒诊断在 ISR 内以 50µs 步进轮询两段各最多 200 次(最长约 20ms)SYNC0 抖动/丢拍导致 SM 看门狗或 Sync 错误掉 SAFEOP;CAN FIFO0(3 帧)溢出丢反馈帧onCsRelease 只做快照+立即重装 DMA,命令处理移至主循环或 PendSV;EXTI10_15 降至 preempt≥1;0xA2 改为状态机异步完成
R-03严重CAN/并发device/CANFD.cpp:284-317、:1255-1321;comm/ethercat_can_bridge.cpp:119、:337CanTxConcurrencyGuard 只屏蔽 EXTI10_15 与本通道 TX 中断;enqueueTx 同时被 Sync0_Isr(preempt 0)/PDI_Isr(preempt 1) 经 EtherCAT 桥调用,可抢占 TX ISR 的 drainTxQueueIsr 与主循环 transmitFrame(注释 281 行声称可防 PDI,与实现不符)软件队列 count 读改写丢失更新;两路同时选中同一空邮箱导致帧被覆盖/丢失所有 enqueueTx/transmitFrame/drain 统一使用 PRIMASK 短临界区(仅包指针/计数与邮箱装填),或把 EtherCAT 侧发送改为单生产者无锁环形队列
R-04严重安全/故障保护comm/ssc/port/dc_app.c:641-651;comm/esc_lan9252.cpp:552-568OP→SAFEOP(主站丢失/SM 看门狗超时)时 APPL_StopOutputHandler 仅调用 EcatCan_ResetSequenceState;不清空 CAN 软件 TX 队列、不下发电机停机/零力矩;过程数据看门狗 0x0420 被放宽至 1s;SPI 链路丢失亦无超时处理通信中断后电机继续执行最后指令或已排队指令最长约 1s 以上,存在机械安全风险(若电机侧无指令超时则升级为致命)定义安全输出态:StopOutput 时清空各通道 TX 队列并广播停机帧;PD 看门狗恢复 100ms 量级;SPI/CAN 指令源分别加超时
R-05严重OTAsys/config.h:359 对 shared/ota_layout.h:48;sys/ota_boot_request.cpp:62-80CONFIG_OTA_CONFIG_WORD_COUNT=8,而布局真源 OTA_LAYOUT_WORD_COUNT=10;擦页重写路径只回写 word0..7每次进 BOOT 请求都会抹掉 word8(ECAT arm 令牌)与 word9(崩溃计数),崩溃门失效、ECAT 刷写语义被破坏直接以 OTA_LAYOUT_WORD_COUNT 定义该常量(删除 config.h 中重复的页地址常量)
R-06严重OTAsys/ota_boot_request.cpp:64-80配置页采用“读→擦整页→逐字写回”,无双页/日志式提交擦除后写回前掉电,整页为 0xFF,BOOT 落入 stay_boot_wait_ota,完好 APP 不再启动,备份标志丢失双页(A/B)+序号+CRC 的原子提交,或只做 1→0 的追加式写标志
R-07严重OTAsys/ota_boot_request.cpp:199-213、:228-229CAN 0x320 “OTA!” 路径在 taskCanRxParse 上下文中同步调用 requestEnterBoot();其余路径也仅关 SPI0/EXTI10_15,库函数 fmc_page_erase 期间 SYNC0/CAN/SysTick 仍开启单 Bank Flash 擦除 20~30ms 期间取指停顿,所有 ISR 被阻塞,EtherCAT 掉线、CAN 丢帧;无鉴权的 CAN 帧即可让 DCU 回 BOOT统一走 requestEnterBootAsync;擦写前先完成外设静默,再在关中断条件下执行;CAN 入口增加鉴权/状态门控
R-08严重电机 OTAsys/motor_ota_relay.cpp:232-234、:1098-1108start() 已在入口以 PRIMASK 加锁(VULN-14 部分修复),但 SPI cancel() 在 preempt 0 ISR 中执行,可插入主循环 process() 的“状态判断→enterState(kTransfer…)”之间;enterState(kIdle) 清锁后主循环又把状态写回活跃态出现“无通道锁的活跃 OTA 会话”,其他总线可再次向升级通道混发;cancel 同时重置环形缓冲头尾,与 bufPop 竞争cancel 只置请求标志,由主循环在单一上下文中执行状态迁移与解锁;锁与状态迁移放在同一临界区
R-09严重电机 OTAdevice/spi/app_spi_cmd_motor_ota.cpp:79SPI 0xD0 cancel 不检查会话来源 s_feed_srcESP32 可中止由 EtherCAT 进料的电机 OTA;若电机已擦除,可能变砖cancel 校验来源,仅允许会话所属通道取消,或要求显式 force 标志
R-10严重安全sys/motor_ota_relay.cpp:23-26、:123-129;仓库根文件 “-”电机 OTA 主密钥 K_MASTER 硬编码于源码(且为可预测常量),AES-128 使用 ECB;nonce 来自以毫秒节拍为种子的 LCG;keyed-CRC32 不是 MAC;根目录 “-” 文件的反汇编中原样包含该常量密钥视同公开;可伪造/重放/降级电机固件(电机侧是否校验 nonce 本仓库不可验证)视为已泄露并轮换;改为每设备派生密钥 + AES-CTR/GCM 或 CMAC;nonce 用 TRNG;从版本库移除 “-” 并评估历史清理
R-11严重CANdevice/CANFD.cpp:1473-1512、:1650-1663;device/spi/app_spi_cmd_can_feedback.cpp:228、:237CAN0→CAN1/2 桥接模式(可由 SPI 0xC2 mode=2 远程打开)在 CAN0 RX ISR(preempt 0) 中调用 bridgeTransmitRaw:不检查 TX 静默、不检查 MotorOtaRelay 通道锁、无并发守卫,且会 abort 其他发送者的在途帧升级期间可打断电机 OTA 固件包;与 transmitFrame 争抢邮箱桥接发送改入软件队列并复用统一守卫;检查静默与 OTA 锁;禁止 abort 他人帧
R-12严重系统device/spi/app_spi_cmd_can_feedback.cpp:88-93、:196;RTE/.../startup_gd32e50x_cl.s:33;regions_GD32E508VE.h:96-970xC1 处理器在 EXTI ISR 中于栈上分配 IdSnapshotTable(~1.35KB)+payload+快照(单次约 1.7KB);栈/堆有三套定义,实际生效栈仅 2KB 且紧贴 .bss 向下增长嵌套中断时栈溢出静默踩坏 .bss 全局变量,表现为偶发、不可复现的故障大缓冲改静态;统一栈/堆定义为单一来源,栈放 RAM 顶部并加大(RAM 约 100KB 空闲),加栈水印/MPU 守护
R-13严重仓库卫生仓库根目录文件 “-”(cfe7725 引入,1,343,675 B)fromelf --text 对 Release .axf 的完整反汇编+符号表被误提交(推断为 -o - 被当作文件名后 git add -A)泄露完整符号/地址布局与密钥常量;仓库膨胀git rm --cached ./- 并在 .gitignore 加 /-;评估 filter-repo 清理历史(本次评审未删除任何文件)
R-14一般EtherCATcomm/ssc/port/dc_app.c:861-872、:892-948;comm/ssc/src/ecatslv.c:951自愈守卫假设“OP 且 bEscIntEnabled=false 不可能”并强制置位;但 Free-Run 模式下该状态合法(ESI 也宣告 Free Run);另 5ms 新鲜度兜底会在 SYNC0 丢失时由主循环强行跑 PDOFree-Run 模式输入仅靠 5ms 兜底刷新;DC 丢失被掩盖、从站不掉 SAFEOP 而继续用陈旧输出(需上板确认)守卫按同步类型区分;兜底仅记诊断不代跑应用,让 SSC 看门狗按规范降级
R-15一般EtherCAT/安全comm/ssc/port/dc_app.c:330-351、:355-3930x2502(回 BOOT)与 0x2503(ESP32 EN)SDO 写不检查 AL 状态与电机运行态(0x2502 仅在 ota_boot_request.cpp:160 拒绝电机 OTA 进行中)OP 运行中被误写即重启 DCU 或切断 WiFi要求 AL≤PREOP 且电机使能关闭,否则返回 SDO abort
R-16一般实时comm/ethercat_sync.cpp:142-147、:161-166PDI_Isr/Sync1 执行期间显式屏蔽 EXTI0(为保护 HBI 两步事务)大块 SDO 时 SYNC0 被延迟上百 µs(VULN-03)HBI 访问改为 ISR 统一代访或使用直接寻址模式缩短事务
R-17一般SPIdevice/spi/app_spi_command.cpp:1317-1320armSpiDmasForNextCs() 仍在 processCommand() 之后调用命令处理慢时 ESP32 下一笔事务落入 DMA 未装窗口,RXORERR/帧损坏(VULN-04)CS 释放后先重装 DMA 再处理命令;ESP32 侧发送前检查 DATA_READY
R-18一般SPIdevice/spi/app_spi_command.cpp:1245-1250按铃待发事件在 ESP32 发起查询帧时被清空,无重发暂存0xC6/0xD2 主动推送事件丢失(VULN-05,影响面较原审计时缩小)引入持久化重发槽并在空闲期重新按铃
R-19一般SPIdevice/spi/app_spi_command.cpp:1135-1147、:1042poll() 中按铃超时处理用 BASEPRI 保护,挡不住 preempt 0 的 CS ISR;cancelRing 不重装 DMAISR 刚装填的新响应被 cancelRing 清掉且 PB6 被拉高,ESP32 收不到通知;陈旧帧留在 TX 缓冲该段改 PRIMASK 短临界区;cancelRing 内重装 DMA
R-20一般SPIdevice/spi/app_spi_command.cpp:339-374帧解析对每个 SOF 候选重算整帧 CRC,畸形 256B 帧可触发约 236 次 CRC在 preempt 0 ISR 中放大耗时(spi_link_v2 CRC 实现在仓库外,耗时待测)先校验长度/版本再算 CRC,限制候选数
R-21一般实时device/CANFD.cpp:1134、:1215、:1374、:1387、:1414;device/usart0.cpp:76-95;app_spi_cmd_motor_ota.cpp:65;motor_ota_relay.cpp:1135printf/LOG 在 EXTI、PDI、CAN TX ISR 中执行;UART 缓冲满时按字节自旋单行日志数百 µs 的 ISR 阻塞;ISR 与主循环并发写环形缓冲索引竞争ISR 内只写无锁日志环或计数器,由主循环输出;满则丢弃并计数
R-22一般CANdevice/CANFD.cpp:1904、:1965-1984refreshFeedbackSnapshot 在临界区外拷贝 s_channelStats;copyIdSnapshotTable 用 BASEPRI 包住约 1.35KB 拷贝,而 RX ISR 为 preempt 0快照撕裂(id 与 data 不配);同时白白压住 preempt≥1 中断双缓冲/序号锁(seqlock)读取
R-23一般CANdevice/CANFD.cpp:1588-1591内容校验 s_lastMcu/s_lastMot 仅按节点号索引,三通道共用不同通道同号节点互相误判按[通道][节点]索引
R-24一般CANdevice/CANFD.cpp:1861-1871、:1891、:1928空通道自动静默条件为“无帧且有错”;正常通道断线 5s 后错误日志与 BUS_OFF 切换日志也被静默;静默状态未经 0xC1 上报真实总线故障被掩盖区分“从未有节点”与“曾在线后掉线”;静默状态上报
R-25一般CANdevice/CANFD.cpp:1294-1321、:1390-1411setTxSilent 不清空该通道软件 TX 队列静默期排队帧在 drain 时以 kErrSilent 无计数丢弃进入静默时清队列并计数
R-26一般故障保护sys/task_runner.cpp:545全系统唯一喂狗点在主循环入口且无条件执行,无任务存活检查调度定时器停摆、ESC 楔死、SPI 死链时仍持续喂狗任务心跳位图全部到齐才喂狗
R-27一般OTAsys/ota_boot_request.cpp:246-257;sys/config.h:338-345复位进 BOOT 前无外设优雅关停(LAN9252 未降级、CAN STB 未置位、SPI/DMA 未停);FWDGT 仍为 DIV64/1874(约 3s)跨复位运行复位瞬间 CAN 在途帧被腰斩;BOOT 等待窗口内若不喂狗将连续看门狗复位(BOOT 侧喂狗需跨仓确认)实现 teardown;复位前延展 FWDGT 或确认 BOOT 周期喂狗
R-28一般OTAdevice/spi/app_spi_cmd_boot_request.cpp:205-2100xB0 总是回 ACK 0xB5,即使随后因电机 OTA 进行中被拒绝上位机误以为已进入 BOOT请求结果同步判定后再回 ACK/NACK
R-29一般电机 OTAsys/motor_ota_relay.cpp:649、:681-692processTransferAck 在任意 kTransfer 状态接受 next_pkt=0xFFFFFFFF,且不拒绝 next16>s_packets_acked+1电机异常/伪造 ACK 可使包号与数据失步严格校验 ACK 范围与状态
R-30一般EtherCATcomm/esc_lan9252.cpp:604-635、:654-659、:683-688pramRead/pramWrite 超时直接 break,不 abort、不返回错误;csrRead/csrWrite 超时静默PRAM 引擎残留 busy,下一事务未定义,数据部分写入超时时写 ABORT 位并返回错误,计数上报
R-31一般EtherCATcomm/ssc/inc/el9800hw.h:45-67;sys/task_runner.cpp:310、:330、:627ENABLE_ESC_INT/ENABLE_AL_EVENT_INT 无条件重新使能 EXTI0/1,抹掉连续性测试或 maskEnter 的屏蔽;DISABLE_AL_EVENT_INT 不屏蔽 EXTI2诊断/测试模式下中断被意外重开,HBI 访问冲突改为引用计数式屏蔽 API
R-32一般EtherCATcomm/esc_lan9252.cpp:366-383(nrstDrive 相关)诊断 nrstDrive 释放复位后不重新初始化 IRQ_CFG/INT_EN、看门狗与 SSC诊断后 PDI 通路失效,需整机重启复位后走完整 ESC 重新初始化流程
R-33一般EtherCATcomm/ssc/src/mailbox.c:243-280;comm/ssc/port/dc_app.c:794-813SM0/SM1 地址或长度与编译期常量不符时只打 WARN;随后守卫(0)又用寄存器值覆盖缓存,与“几何常量化”设计矛盾主站错误配置不会被拒绝,邮箱行为不确定不匹配时以 INVALIDMBXCFGINPREOP 拒绝
R-34一般EtherCATcomm/ssc/port/hw_gd32exmc.cpp:183-191HW_SetLed 对奇地址 0x0139 做 2 字节 CSR 写;对 0x0138 的 2 字节写会覆盖 0x0139;写值 0x0001 未置 override 使能位LED 指示错误或改写相邻寄存器按字节写并设置正确位
R-35一般构建GD32E508_DCU_APP/GD32E508_DCU_APP.cproject.yml源文件名大小写与磁盘不符(adc.cpp/canfd.cpp/timer.cpp/timer.h vs ADC.cpp/CANFD.cpp/Timer.cpp/Timer.h)只能在 Windows 大小写不敏感文件系统构建,CI/Linux 失败统一文件名大小写
R-36一般构建cproject.yml(-IG:/Robot_v2/DCU/spi_link 与 ../../spi_link);_syntax_check.bat共享协议 spi_link_v2 位于仓库外并以绝对路径引用仓库无法独立复现构建;帧格式/CRC 无法随本仓审查作为 git submodule 或 vendored 目录纳入
R-37一般构建cproject.yml未启用 -Wall/-Wextra/-Werror(仅 -Wno-register)潜在缺陷不被编译器暴露逐步开启告警并清零
R-38一般仓库卫生.gitignore;comm/ssc/port/__pycache__/*.pyc;_syntaxcheck_stubs/;.trae/.trae/ 被忽略但 10 个文件已跟踪;*.html 全局忽略(docs 下 HTML 本地需 -f);pyc、本机路径脚本进仓仓库噪声与规则失真清理跟踪文件,*.html 规则收窄到根目录产物
R-39一般构建comm/ssc/port/ecat_def.h:620-655;DCU_ESI.xml;sys/config.h:177-180APP 版本 1.7.4 单一定义良好,但 ESI RevisionNo/DEVICE_SW_VERSION 未随版本更新;ota_layout.h 在 APP/BOOT 各存一份主站无法依 ESI 区分固件版本;布局副本漂移风险构建时生成 ESI 版本;ota_layout.h 用子模块共享
R-40一般文档README.md路径 /workzone/…、temp_sensor 模块、整套 C 风格 API(app_init、task_runner_run_pending 等)均已不存在;未覆盖 comm/、OTA、AES、看门狗新成员被误导按当前 C++ 静态类结构重写
R-41一般质量(仓库整体)无 tests/、无 CI 工作流;提交 cfe7725 一次混合约 10 个主题并夹带 “-” 文件回归无法自动发现;历史难以二分定位建立主机侧单元测试(协议解析、OTA 状态机、配置页)与 Gitea Actions 构建
R-42建议SPIdevice/spi/app_spi_command.cpp:764-812err_crc_mismatch 等分原因计数器仅在 CONFIG_SPI_APP_LOG_ENABLE(当前 0)时自增0xA4 诊断恒报 0计数与日志开关解耦
R-43建议实时device/CANFD.cpp:599、:601CAN 中断设置了不同子优先级,在 PRE4_SUB0 分组下无效误导读者去掉子优先级参数并注释说明
R-44建议故障保护sys/hardfault.cpp:15-20、:94-137rawPutc 等待 TBE 无超时;未使能 MemManage/BusFault/UsageFault;不保存崩溃现场故障难以事后定位使能细分故障,保存寄存器快照到 noinit RAM 后复位
R-45建议质量device/canfd.h:36、42-43、65-67;CANFD.cpp:386、501、1132-1136注释与实现不一致多处(kErrBusOff 已死码、时钟打印仍写 2Mbps 等);遗留“幽灵帧 0x100”调试打印在热路径可维护性下降清理注释与调试打印
R-46建议EtherCATDCU_ESI.xml;gen_eeprom.py;ethercat_pdo_size.h 注释Vendor ID 为 0x00000000;gen_eeprom docstring 过时;注释称 SM3 止于 0x1F67,实际 0x1F87(PDO 大小 384/600B 在 ESI/EEPROM/代码间一致)量产与 ETG 一致性认证受阻申请 ETG Vendor ID 并同步注释
R-47建议实时sys/critical.h:69-75新增 RT_CRITICAL_PREEMPT0_SAVE 仅在 motor_ota_relay.cpp:1099 使用一次与 preempt 0 共享数据的其余路径仍用 BASEPRI梳理所有与 preempt 0 ISR 共享的数据并统一临界区策略
+ +

4. 既有评审结论跟踪

+

4.1 docs/audit_ecat_spi_wifi_ota_compatibility.md(2026-09-18,v2.0)

+

修订跟踪已另存为 docs/audit_ecat_spi_wifi_ota_compatibility.rev2026-10-19.md,原文件保留并在文首加注指向本次评审。

+
原编号原结论当前状态证据本次对应
VULN-01SPI CS ISR 与 SYNC0 同处 preempt 0 且同步执行耗时命令仍存在app_spi_command.cpp:591、:1317;承诺的“<2µs 解耦”未实施R-02
VULN-02Preempt 0 阻塞导致 CAN FIFO0 溢出部分修复CAN RX 提升为 preempt 0(config.h:373),FIFO 改为丢新不覆旧(CANFD.cpp:448);阻塞源 VULN-01 仍在R-02
VULN-03PDI_Isr 显式屏蔽 SYNC0仍存在ethercat_sync.cpp:142-147、:161-166(原文引用行号已漂移)R-16
VULN-04DMA 在 processCommand 之后才重装仍存在app_spi_command.cpp:1317→1320R-17
VULN-05按铃事件被查询帧抹除仍存在(影响面缩小)app_spi_command.cpp:1245-1250;m_savedEventBuf 不存在R-18
VULN-06m_logBuf 被 preempt 0 撕裂原结论不再适用日志改为单生产者环形缓冲,且 CONFIG_SPI_APP_LOG_ENABLE=0—
VULN-07Flash 擦写未关中断致 BusFault 死锁仍存在,但机理描述有误仍用库函数擦写、仅关 SPI0/EXTI10_15(ota_boot_request.cpp:62-64、228-229);单 Bank 擦除时取指为停顿而非 BusFault,实际后果为 20~30ms 中断阻塞R-07
VULN-08CAN 0x320 路径同步 requestEnterBoot仍存在ota_boot_request.cpp:199-213R-07
VULN-09复位前无外设优雅关停仍存在ota_boot_request.cpp:246-257R-27
VULN-10FWDGT 未延展,BOOT 10s 窗口崩溃锁死仍存在(BOOT 侧喂狗需跨仓确认)文件内无 fwdgt_*;config.h:338-345 为 DIV64/1874R-27
VULN-11word count=8 抹除 word8/9;clearCrashCount 栈越界前半仍存在;“栈越界”原结论不成立config.h:359=8;clearCrashCount 走 writeWord 路径(ota_boot_request.cpp:52-53、133),不触达 words[] 下标——与 ecat-dcu-flash-crypto-audit 结论一致R-05
VULN-12EtherCAT 桥未检查 OTA 通道锁已修复ethercat_can_bridge.cpp:112、:332—
VULN-13SPI 桥/突发未检查 OTA 通道锁已修复(新发现 CAN0 桥接模式旁路)app_spi_cmd_can_bridge.cpp:83;app_spi_cmd_can_burst.cpp:85;旁路见 R-11R-11
VULN-14start() 加锁前存在漏包窗口部分修复motor_ota_relay.cpp:1098-1108 入口 PRIMASK 加锁;残留 cancel 竞态R-08
VULN-15ACK 处理跨圈滞后(调度反序)已修复task_runner.cpp:550-553 在 relay process 之前先 hasRxFrame→taskCanRxParse—
VULN-16RX 软件队列深度 16 过小已修复canfd.h:277 深度改为 64—
审计总评自评“98.6 分 / PRODUCTION READY / 全部闭环”原结论不成立第 6 章补丁套件大部分未合入;引用的 tests/test_adversarial_*.py 在仓库中不存在—
+

4.2 compose/spec、.trae 与 README

+

汇总于 docs/compose/spec/REVIEW_STATUS_2026-10-19.md。

+
记录原结论/内容当前状态
docs/compose/spec/ecat-dcu-flash-crypto-audit.mdDCU 刷写无载荷加密;word count=8;CAN 路径同步;无 teardown/fwdgt;BOOT 侧不可验证仍成立;补充:BOOT 侧经跨仓核实 arm 门可被 0x2502 无鉴权打开(R-01)
docs/compose/spec/lan9252-perf-audit.mdP1 差分写 ESC、P2 csrRead verify 分级已实现:config.h:134 SPARSE=1、:143 DIFF=1;esc_lan9252.h:84 csrRead(verify)。上机对拍仍待做;front-matter updated 日期与提交时间不符
docs/compose/spec/ecat-wkc-periodic-dip.md主因 B:输出侧每 256 拍强制全量读机制仍存在(ethercat_pdo.cpp:114-134),未见修复提交;仍待现场 A/B 对拍
docs/compose/spec/tiered-pdo-mapping.mdstatus: designed,按电机数分档收缩 SM3未实现:全仓无 tier 相关代码,SM3 仍为 600B
docs/compose/spec/warm-jump-ecat-probe.md起板探针改为 BYTE_TEST 放行已实现并保留(esc_lan9252.cpp 使用 LAN9252_BYTE_TEST_VALUE)
.trae/specs/fix-ethercat-realtime-comm-riskss_periodicSeq、safe* 接口、PDO 三缓冲被后续 SSC 集成取代:periodicIsr/三缓冲桥已删除,PDO 由 SSC 3-buffer SM 完成
.trae/specs/fix-ecat-postaudit-risksH1 safe* 收窄;M1 SYNC0 RAM 化;M2 NVIC 分组前移;M3 删 readBlockH1/M3 已落地(safe*、readBlock 均已不存在);M1 已落地(ethercat_sync.cpp:112、:188 .ramfunc);M2 已落地(initial.cpp:222)
.trae/specs/fix-ecat-pdo-and-runtime-issuesS1 PDI 偏移分离、S2 process 桥、S3 AL 守卫、M4-M7S1/S2 被 SSC 架构取代;S3 部分保留(ethercat_slave.h:32 getAlState);M4-M7 随旧路径删除
.trae/documents/cleanup-residual-low-risk-optimizations.md13 项低风险清理抽查均已落地:canfd_diag_t、m_ringTxLen、s_pushCount 已删除,sys/hardfault.h 已删除,spinDelay/armRingPending 已提取,ADC 匿名 namespace 已合并
README.md工程结构说明大面积过时(见 R-40)
+ +

5. 优先级修复路线图

+ + + + + +
阶段时限建议事项对应问题
P0 止血1 周内轮换电机 OTA 密钥并移出版本库;配置页 word 数改为 10;0x2502/CAN 0x320 加状态门控与临时口令;StopOutput 清空 CAN 队列并下发停机;PD 看门狗回到 100ms 量级R-01 R-05 R-07 R-04 R-10 R-13 R-15
P1 实时性重构2~4 周SPI 命令处理移出 preempt 0 ISR(CS ISR 只快照+重装 DMA);统一 CAN TX 并发模型(含 CAN0 桥接);ISR 内禁 printf;0xC1 大缓冲静态化、统一栈定义并加栈守护R-02 R-03 R-11 R-12 R-16~R-22
P2 OTA 可靠性1~2 月镜像签名验签(BOOT 协同);配置页 A/B 原子提交;电机 OTA cancel 改主循环单上下文;AES-CTR/GCM+TRNG nonce;复位前外设 teardown 与看门狗策略R-01 R-06 R-08 R-09 R-10 R-27~R-29
P3 EtherCAT 规范性1~2 月Free-Run/DC 丢失处理按规范降级;PRAM 超时 abort;中断屏蔽改引用计数;邮箱几何不符即拒绝;Vendor ID/ESI 版本R-14 R-30~R-34 R-46
P4 工程化持续文件名大小写、spi_link 纳入子模块、开启 -Wall、.gitignore 清理、README 重写、主机侧单元测试 + Gitea Actions CI、提交按主题拆分R-35~R-41
+ +

6. 总结评分

+ + + + + + + +
维度权重得分理由
实时性与中断设计20%45SPI 命令仍在 preempt 0 同步执行;临界区策略与中断级别不匹配
通信协议(EtherCAT/SPI/CAN)20%60PDO 尺寸三方一致、差分写/RAM 化扎实;CAN TX 并发与 SSC 边界处理有缺口
安全与故障保护20%30刷写无鉴权、密钥硬编码泄露、通信丢失无安全输出态
OTA/Bootloader 可靠性15%40通道锁已加,但配置页非原子、word 数错配、cancel 竞态
代码质量与可维护性15%60注释详实、无 TODO/#if 0 残留、清理计划已落实;大文件与注释漂移、无测试
构建与仓库卫生10%45“-” 产物与密钥进仓、外部绝对路径依赖、大小写不一致、无告警
综合100%48功能完整、调试可观测性强,但距可量产尚有 P0/P1 级工作
+

亮点

+

本报告由多专家视角静态评审生成;所有行号基于 d8b3c97。代码变化后请以最新代码复核。

+
\ No newline at end of file