结论:Subaru Global safety 的 TX 权限极窄:转向帧 0x122 受扭矩与请求位门约束,而 0x221 ES_Distance 只允许取消——任何非 inactive_gas=1818 的 Cruise_Throttle 或未设置 Cruise_Cancel 都被拒,主动油门、制动或巡航 RPM 命令一律不放行。该快照下 alphaLongitudinalAvailable=False,不能因限值结构存在就向插件授予纵向执行权限。
本文依据固定源码快照的 subaru.h、车型接口和相邻安全测试做静态分析,不证明目标固件、线束、ECU 或实车安全。本文覆盖 Global 模式;它与 Preglobal 是不同安全钩子,能力不能互相继承。
模式与总线矩阵:Gen2 只搬了三组 RX
Global 选择 subaru 安全模式,Gen2 额外设置 GEN2 参数。subaru_init() 按 Gen2 标志选择两组 RX/TX 总线表,没有纵向 TX 表分支。一个常见误解是「Gen2 把全部 RX 移到 bus 1」——实际只有轮速、制动、巡航三组从 bus 0 改到 bus 1,油门与驾驶员扭矩仍留在 bus 0。
| 报文职责 | Gen1 | Gen2 | 钩子使用 |
|---|---|---|---|
| 0x40 油门、0x119 驾驶员扭矩 RX | bus 0 | bus 0 | 两代相同 |
| 0x13A 轮速、0x13C 制动、0x240 巡航 RX | bus 0 | bus 1 | Gen2 的 alt bus 影响这三组,不能把全部 RX 一起移到 bus 1 |
| 0x122 ES_LKAS TX | bus 0 / 8 字节 | bus 0 / 8 字节 | 两代均检查扭矩与请求位 |
| 0x221 ES_Distance TX | bus 0 / 8 字节 | bus 1 / 8 字节 | 均只允许取消,Cruise_Throttle=1818 |
| 0x321/0x322/0x323 HUD TX | bus 0 / 8 字节 | bus 0 / 8 字节 | 白名单与继电器检查;无本模式逐字段校验 |
五组 RX 均要求 8 字节、8 位累加校验、四位计数器和存活检查;声明频率依次为油门 100 Hz、扭矩 50 Hz、轮速 50 Hz、制动 50 Hz、巡航 20 Hz。这些频率用于健康检查,不等于每帧独立实时截止时间。subaru_get_checksum()、subaru_get_counter()、subaru_compute_checksum() 定下字节 0 存校验和、字节 1 低四位为计数器;校验值为地址两字节加字节 1 起的数据之和并截断为 8 位。
校验与计数器:一个已知的盲点
一个值得写进契约盲点的现象来自离线探针:把已打包 0x221 帧的字节 4 异或 0xFF、保持原校验字节不变,两代仍能通过 TX 钩子。这说明该数据字节及由此产生的校验和失配不在本模式的 TX 专属检查内。需要强调边界:这不意味着 ECU 会接受畸形帧,只是固件这一层没有拦。
| 项目 | 规则 | 边界 |
|---|---|---|
| 校验和 | 字节 0 存校验和;地址两字节加字节 1 起数据求和截断为 8 位 | 8 位累加,非通用 CRC |
| 计数器 | 字节 1 低四位 | 四位回绕,配合存活检查 |
| TX 校验盲点 | 改字节 4 保持原校验字节仍可通过 TX 钩子 | 不在本模式 TX 专属检查内,不代表 ECU 接受 |
转向、纵向与转发边界
subaru_tx_hook() 对 0x122 解码 13 位有符号转向扭矩并反转符号,检查请求位。Gen1 最大扭矩 2047、上升/下降分别 50/70;Gen2 为 1000、40/40。两代共用实时差 940、驾驶员余量 60、倍数 50,以及至少 7 帧有效请求、最多 1 帧无效请求和 144 ms 最小间隔的容忍配置。这些是固件限值,不等于主机控制器一定按相同步长构帧。
纵向一侧,源码定义了较多 SUBARU_LONG_LIMITS 字段,但当前 TX 钩子只在 0x221 读取其 inactive_gas=1818,没有放行主动油门、制动或巡航 RPM 命令。与之对应,接口显式关闭自控纵向能力。
同时,两代的 0x122 与 HUD TX 均标 check_relay=true,若本机发送总线出现同地址原车帧,可触发共享继电器故障;0x221 为 check_relay=false。该模式无专属 fwd 钩子,通用转发只在 bus 0 与 bus 2 之间;Gen2 的 bus 1 不是该转发对。不能只看上层相机/网关接线位置就假定 0x221 已被正确转发或替代。
状态侧,subaru_rx_hook() 对 0x119 读取 11 位驾驶员扭矩并反转符号;轮速解析四轮 13 位原始值,只要任一非零即认为移动,并以均值形成速度。通用 RX 门继续处理踏板退出。
验证与插件准入
三项原钩子离线探针用真实 DBC 打包 0x221 取消帧并调用编译版 safety_tx_hook():Gen1 仅 bus 0、Gen2 仅 bus 1 可通过;取消位缺失或油门从 1818 变为 1819 都被拒。相邻 test_subaru.py 覆盖 Gen1/Gen2 扭矩、请求位及取消帧;本机运行该模块 64 项,12 项跳过,其余通过。
- 身份插件需证明 Global Gen1/Gen2、DBC 和物理总线布局;Preglobal、Hybrid、角度 LKAS 的能力不能继承本模式推断。
- 车辆输入插件保留五组 RX 的来源与时间戳;Gen2 特别区分 bus 0 的油门/扭矩与 bus 1 的轮速/制动/巡航。
- 控制插件只提交转向意图和受限取消请求;安全模式读回、CRC/计数、继电器、失联降级仍由独立 MCU/网关裁决。
- 验证需覆盖错总线、校验/计数故障、巡航边沿、驾驶员反扭矩、请求位切断、0x221 非活动油门和 HUD 载荷,再进入台架与受控场地。
HUD 三帧仅做通用地址/总线/长度白名单及继电器检查,未在本模式限制载荷字段。自制硬件应把这些帧的构造权留给可信任网关,限制模板与发送节拍,避免普通插件直接写原始 CAN。当前无目标板或实车验证。
常见问题
Subaru Global 支持自控纵向吗?
不支持。该快照下 alphaLongitudinalAvailable=False,普通参数路径不会启用自控纵向;subaru_init() 也没有纵向 TX 表分支。当前 TX 钩子只在 0x221 读取 inactive_gas=1818,任何非该值的 Cruise_Throttle 或未设置 Cruise_Cancel 都被拒。
Gen2 是把所有 RX 都移到 bus 1 吗?
不是。Gen2 只把轮速、制动、巡航三组从 bus 0 改到 bus 1,油门与驾驶员扭矩仍留在 bus 0。不能把全部 RX 一起移到 bus 1,否则会读错来源。
改了 0x221 的数据字节还能通过 TX 钩子,是不是说明固件有漏洞?
该数据字节及由此产生的校验和失配不在本模式的 TX 专属检查内,所以按探针做法仍能通过 TX 钩子;但这不等于 ECU 会接受畸形帧。这里应把它写成契约盲点,而不是定性为整车级缺陷。
为什么不能只按接线位置判断 0x221 是否被转发?
因为该模式没有专属 fwd 钩子,通用转发只在 bus 0 与 bus 2 之间,Gen2 的 bus 1 不是该转发对;而 0x221 的 check_relay=false。只看上层相机/网关接线位置,无法推断 0x221 已被正确转发或替代。
延伸阅读
- Volkswagen 与 Subaru:两套车型接入的差异在哪 —— 对照另一品牌的总线/平台分支。
- Toyota panda safety 模式:RX/TX 表与转向限值 —— 用另一个安全模式对照「只允许取消」的写法。
- 从使能到车轮:执行链上的八道门,以及它们各自不保证什么 —— 说明固件限值不等于主机一定照此构帧。
- Hyundai 与 Honda 的车型接入:经典 CAN 与 CAN FD 的分野 —— 补齐同类「两代总线差异」的对照。
参考资料
- 项目 02 ——
openpilot-research/SUBARU_GLOBAL_PANDA_SAFETY_DEEP_DIVE.md(取用了 Global Gen1/Gen2 总线矩阵、TX 取消帧约束、转向限值与三项离线探针结论)。 - 项目 02 ——
openpilot-research/SUBARU_PREGLOBAL_PANDA_SAFETY_DEEP_DIVE.md(仅用于确认 Preglobal 是不同安全钩子、能力不可继承)。
说明:本文为对固定源码快照的静态结构分析,未运行完整测试套件、未连接硬件、未验证目标车型的真实参数组合。文中所有阈值、行号索引与配置均出自源文档,标注为未验证的结论保留其原有边界。
更新记录
首次发布 2026-10-11 最近核对:2026-10-11
发表回复