多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

嵌入式系统功能安全与信息安全:开发工具链的实战应用

嵌入式系统功能安全与信息安全:开发工具链的实战应用 2023上海国际嵌入式大会的日程里“功能安全与信息安全”相关专场是现场座位最不好找的区域之一。嵌入式系统复杂度逐年走高单靠手工测试、人工代码走查来保证稳定安全已经明显吃力。功能安全、信息安全这两件事不再是“合规部门”的文档任务而是实实在在落在开发工具链上的硬功夫。这篇回顾想聊聊我在会场听到、看到并验证过的一些思路主要围绕开发工具怎么帮助嵌入式系统稳住安全底线适合正在做汽车电子、工业控制、医疗设备或任何对可靠性有硬性要求的嵌入式工程师参考。我自己做嵌入式开发有年头了早年跑过不少“裸奔”项目后来做带功能安全要求的域控制器发现工具链的投入直接决定了项目后期会不会返工。这次大会给我的整体感受是工具不再是可有可无的辅助而是把安全标准翻译成工程动作的关键中介。下面按会场讨论的主线展开。1. 从“两张皮”说起功能安全和信息安全为什么会走到一起1.1 功能安全防“失灵”信息安全防“使坏”功能安全追求的是系统在故障状态下仍然可控或者至少能安全地停下来。ISO 26262、IEC 61508这些标准讲的都是如何降低系统性失效和随机硬件失效的风险。信息安全则完全不同它要防的是外部恶意输入导致的非预期行为。以前这两个领域分属不同团队、不同工具链甚至在不同阶段介入项目。但现实中的嵌入式系统越来越像一台联网的小型计算机一条指令既能因为内存踩踏崩溃也能因为被注入恶意payload而崩溃表现几乎一样。在会场听一位做车身域控制器的工程师讲他们一个项目里同时要过功能安全ASIL B和公司的信息安全红线要求两边分别提了一堆测试用例结果有一大半是重叠的。这个观察很真实。系统失效和被攻击失效最终的故障模式可能是同一条程序跑到不该跑的分支、传感器数据被篡改、通信报文时序错乱。功能安全关注“故障怎么发生”信息安全关注“攻击怎么进来”但落地到代码层面都需要验证控制流、数据流和时序是否符合预期。这也是为什么本次大会把这两块放在一起谈不是因为概念上要强行绑定而是因为开发工具在支撑两者时正在走向统一。1.2 开发工具是标准与代码之间的“翻译官”标准写的是一套抽象要求比如“应尽量减少系统性失效”“应能检测数据篡改”但工程师面对的是几十万行C代码。把抽象要求翻译成具体的代码走查规则、测试用例、覆盖率指标手工做既慢又容易漏。开发工具在这里起到的作用是用机器可执行的检查项去替代人工臆测。静态分析工具能扫出MISRA C违规、可疑的空指针解引用动态测试工具能注入故障并观察系统反应安全通信工具能模拟攻击报文并验证加密机制是否真正生效。这些工具表面上各管一段但设计逻辑高度一致先建立“预期行为模型”再通过施加异常输入或者故障检验系统是否能守住安全边界。区别只在于异常的种类是随机硬件故障、逻辑设计缺陷还是恶意构造的数据。这种共性恰恰是功能安全和信息安全能被一条工具链承接的基础。2. 功能安全开发工具的深层能力从静态分析到故障注入2.1 静态代码分析与形式化验证静态分析工具已经是功能安全项目的标配。MISRA C规则检查、数据流分析、控制流分析这些不是新鲜功能但工具的实现深度差别很大。廉价方案做个字符串匹配也能叫“MISRA检查器”但真正对功能安全认证有用的必须能识别跨函数调用、跨文件的全局数据流问题。比如一个被中断服务程序修改的全局变量在普通函数里被读取没有volatile声明这种问题靠人工review很难每次都抓住静态分析工具却能精准定位。形式化验证工具在会场被反复提及但实际使用者仍属少数。原因在于它对工程团队的数学功底有要求而且对现有代码的建模代价不低。不过对于一些安全状态机、通信协议的状态转换形式化验证确实能发现边界条件下才触发的死锁或状态遗漏。我的经验是新设计可以在架构阶段用形式化工具验证核心逻辑老代码则不必强行建模先用静态分析守住底线更划算。2.2 故障注入测试代码覆盖之外的隐藏保障功能安全里有一类经典测试叫故障注入测试它的目的不是验证“功能是否正确”而是验证“当某个部件发生故障时系统是否能安全降级”。比如ADC采集到一个超出物理上限的电压、CAN总线长时间无报文、存储器的ECC校验报错这些都属于故障。测试工具会通过脚本或硬件接口向目标系统强制注入这些故障然后观察系统监控机制是否触发、是否进入安全状态。这里关键的不是工具能不能注入故障而是故障模型是否贴近实际。我见过不少团队用一个简单的信号变更为测试用例结果系统监控逻辑确实被触发了但注入的故障模型过于理想化根本覆盖不到现实中的毛刺和间歇性故障。好的故障注入工具应该支持按毫秒级时序注入、支持多通道同时故障、支持故障持续时间控制这样才能模拟真实的物理失效过程。会后和几位同行聊大家公认“故障注入用例的设计能力”比工具本身更影响测试质量工具只是把想法快速落地的手段。2.3 时序分析和调度验证实时系统的隐形杀手功能安全测试中还有一个容易被忽视的维度是时序。嵌入式系统出问题很多时候不是数据算错了而是算得太晚。中断响应时间、任务最坏执行时间WCET、资源抢占的阻塞时间这些如果验证不充分即使逻辑全对系统也会在实际负载下超时。开发的工具里比较有用的包括基于跟踪的运行时分析工具它通过处理器调试接口实时记录执行轨迹计算出每个任务的真实执行时间和调度延迟。我在一个电机控制项目里遇到过这样的问题控制算法在实验室低负载下一切正常但到了整机联调时因为另一路通信中断频繁抢占核心CPU时间导致控制周期偶发抖动。当时靠的是跟踪工具抓到了中断嵌套的时序证据否则很难说服软件团队去修改中断优先级。不要凭感觉做实时性优化要让数据说话。3. 信息安全开发工具嵌入式系统的另一条防线3.1 安全启动与密钥管理工具链里最容易忽略的一环说到信息安全很多嵌入式工程师第一反应是加密算法、SSL/TLS。但安全启动才是系统的第一道门。没有可信根后续的加密通信、安全更新都无从谈起。安全启动链路里BootROM需要验签BootloaderBootloader再验签应用程序每一级的公钥都存储在硬件安全模块HSM或一次性可编程存储器里。这个链路的实现本身不难难的是密钥生成、存储、轮换和吊销的管理流程。这次专门有讲师提到一个很有意思的实践用硬件安全模块本身的开发工具来生成密钥对并且把私钥直接存放在HSM内部不允许导出。这意味着即使开发机被攻破攻击者也拿不到签名私钥。但副作用是如果私钥意外丢失整个产品序列将无法再发布升级包。所以在项目中既要配置HSM工具做密钥全生命周期管理也要设计好备份策略和流程这不是纯技术问题而是流程和工具的结合问题。3.2 安全通信与漏洞扫描攻击者视角的验证功能安全测试站在“系统自己的角度”看问题信息安全测试则要站在“攻击者的角度”看问题。开发工具在这方面的支持包括协议模糊测试fuzzing、漏洞扫描、异常报文注入等。协议模糊测试工具会自动生成大量畸形的协议报文发送给被测设备观察其是否崩溃或进入异常状态。这类测试在发现协议解析器的边界问题方面非常有效。有一个典型例子某个ECU的UDS诊断服务在解析长度字段时没有严格校验模糊测试工具发送一个超长长度字段后设备直接进入了bootstrap模式。这种问题靠人工测试很难发现但工具可以自动并持续地制造变化。信息安全测试工具还有一类重要功能是“安全通信中间件的一致性验证”。比如车载领域常用的SecOC安全车载通信或者工业里的TLS、DTLS工具需要验证MAC计算是否正确、防重放窗口是否生效、密钥更新是否遵循规范。这类验证比普通的功能测试更细因为要处理异常加密参数、重复报文、序列号跳变等特殊情况。真正动手做过的工程师都知道信息安全的最大难点往往不是算法本身而是协议状态机在异常输入下的行为是否符合预期。3.3 工具链组合与安全认证的关系信息安全认证如ISO 21434、IEC 62443标准都有“开发过程”维度的要求审计员不仅看结果还会检查开发过程中是否用了合适的工具以及工具自身是否可信。这就带出一个容易被忽视的问题开发工具本身也是软件它会不会有漏洞如果工具在生成代码或者配置参数时出错整个安全链路的根基就动摇了。因此有些工具会提供“输出校验/哈希校验”机制构建系统可以自动校验工具链输出物的一致性防止工具被篡改或版本不一致导致的安全隐患。在项目管理上建议把开发工具的版本、许可证、构建环境固化下来形成可复现的构建环境。这一点在安全关键领域的重要性不亚于代码本身的正确性试想一个负责验签的脚本因为工具版本升级而变化产品的安全启动链路虽然功能正常但审计时无法证明构建过程可信依然会非常头痛。4. 实操参考用开发工具打通“功能安全信息安全”项目闭环4.1 从需求、测试用例到验证报告的规范化设计开发工具发挥最大价值的前提是把安全需求分解成可执行验证的测试用例。以一条典型需求为例“当车速信号无效时系统应在100ms内切换到安全状态。”这句话要变成测试用例需要先定义“无效”的具体类型信号缺失、超范围、校验失败再定义安全状态的观测方法通过CAN报文或状态寄存器。好的管理工具能把需求、测试用例、测试结果和覆盖率全部串起来生成可追溯的验证报告。在功能安全和信息安全认证中“可追溯性”往往是最花费时间的环节因为审计员最爱问“这条需求对应的测试证据在哪里”。建议用矩阵式的追踪表格维护“安全目标到功能需求再到软件需求再到测试用例”的映射关系。开发工具辅助追踪不仅仅是记录数据更重要的是当需求发生变更时能自动标记受影响的下游用例避免漏测。这一点在快速迭代的项目里尤其有价值否则需求一改很容易出现测试集和实现不同步的老问题。4.2 典型工具选型与工作环境配置这里挑几个常见的工具组合来讲任务目标工具类型主要关注点静态代码分析MISRA检查、数据流分析工具规则覆盖率、误报率、能否自定义规则动态运行时测试单元测试、集成测试工具插桩代价、目标平台支持、报告格式故障注入基于硬件或脚本的故障注入工具故障模型丰富度、时序可控性、自动化程度时序分析跟踪调试器、逻辑分析仪配套工具时间戳精度、对目标CPU侵入性安全通信测试协议模糊测试、中间人测试工具协议类型支持、测试用例生成策略安全启动配置HSM配置与密钥管理工具密钥生命周期管理、审计日志配置工作环境时有一个容易被新手忽略的细节工具链的版本一致性。一套工具的不同插件之间如果版本不匹配往往表现为“上次能跑的用例这次跑不过”或“覆盖率数据对不上”。项目团队最好把工具链版本清单纳入版本管理和代码一起打tag。我在实际项目里就吃过这个亏一次工具版本更新后编译出的代码行为差异导致故障注入测试结果和上一版完全不同定位了一天才发现是编译器优化行为变了。4.3 一个具体例子CAN总线故障注入的完整流程以车载ECU开发为例利用支持功能安全和故障注入的CANoe车载总线开发环境进行测试时硬件接口卡的选择很重要。较高端型号的CANoe硬件接口支持更精细的故障注入能力包括按位错误注入、总线信号干扰、节点选择性休眠/唤醒等。工程师可以通过CANoe的CAPL脚本语言定义故障场景比如“在报文ID 0x123的第5个数据字节注入一位错误”或者“在车速信号传输期间连续丢弃3帧报文”。实际执行流程一般分为四步第一步是在CANoe中建立仿真总线环境加载被测ECU的CAN数据库文件第二步是用Panel模块快速设计一个控制界面用于手动触发特定故障第三步是通过CAPL脚本实现自动化的故障注入序列并同步记录被测ECU的响应报文第四步是分析响应数据判断ECU的故障处理逻辑是否符合预期例如是否发出故障码、是否进入降级模式、响应时间是否在要求范围内。我第一次跑这个流程时有个深刻的教训故障注入的时机必须精确到报文发送窗口内否则无法模拟真实的物理位错误。后来依靠CANoe硬件的精确时间戳同步和总线级错误注入功能才真正让故障事件和总线信号严格对齐。这类测试的价值在于它能复现实际车辆现场偶发的通信问题让开发人员在实验室里就能定位出软件逻辑漏洞。5. 常见问题与排查技巧实录工具落地中的各种“坑”5.1 问题速查表常见问题可能原因排查思路静态分析误报太多规则配置过严或代码风格特殊先跑默认规则集再逐步增加自定义规则记录每次增加引起的误报变化覆盖率数据缺失插桩方式不匹配目标编译器检查插桩工具和目标编译器的版本兼容性必要时改用硬件分支跟踪时序分析结果异常追踪调试影响了实时性优先使用片上嵌入式跟踪宏单元而不是软件插桩故障注入后目标复位故障模型过强或保护机制过敏感逐级调整故障强度从信号异常到总线错误逐步试验安全启动验签失败密钥错配或镜像拼接顺序错误检查启动镜像哈希的计算范围确认签名数据和镜像分区对齐模糊测试导致设备假死目标设备缺少看门狗或未恢复在测试中增加看门狗喂狗脚本并对测试用例做隔离批处理之所以把这些问题整理出来是因为这些坑我都或多或少踩过。尤其是故障注入后目标复位的问题我遇到过一次为了模拟ADC故障直接把采样值强制拉满结果触发过压保护直接系统复位。实际上真实世界的传感器故障往往是渐变式漂移不是阶跃式满量程突变。这类“测试模型过于极端”的问题通常需要回归到物理特性去校准故障参数。5.2 功能安全与信息安全工具如何协同工作工具链之间也需要“接口对齐”。比如功能安全测试用到的故障注入视图和信息安全测试用到的异常报文视图最后都要汇入同一个问题追踪系统。分工上功能安全侧更多是在“系统内部制造故障”信息安全侧是在“外部接口注入恶意数据”但二者共用一套观测手段运行时日志、跟踪数据、报文记录。建议在项目早期就统一日志格式和上报接口这样无论哪一侧发现异常都能用同一套分析工具快速定位。还有一点值得注意功能安全和信息安全的测试环境有时会互相干扰。功能安全故障注入可能触发系统复位而这恰恰是信息安全测试中一种可以利用的异常状态。反过来信息安全模糊测试发出的畸形报文也可能掩盖功能安全测试的故障判断。解决方法是把两类测试放在不同测试阶段或不同测试通道中执行必要时用独立的测试网络和存储空间防止数据串扰。5.3 团队能力建设与工具链长远维护工具发挥持久价值的前提是有人真正懂它。最近信息安全工程师相关的认证考试如软考信息安全工程师方向热度上升这反映出行业对专业人才的需求在增加。嵌入式团队不可能每个人都成为信息安全专家但至少需要有一名核心成员能读懂安全标准的工具要求、能设计测试用例、能维护工具环境。这样遇到工具链问题才不会出现“只会点按钮、不会改脚本”的尴尬局面。从长远看开发工具链的建设不是一个项目结项就结束的任务。随着编译器版本升级、芯片平台迭代工具链本身也需要持续验证和更新。建议在每个项目的开始和结束时都做一次工具链健康检查包括许可证是否齐全、插件版本是否一致、自动化脚本是否仍然可用。这些工作比较琐碎但关键时刻能省下好几个调试日。最后分享一点个人习惯我在多年的嵌入式安全项目开发中养成了一个习惯每次代码评审之后都会用静态分析工具做一次增量扫描把新增代码的违规警告清零而不是攒到版本发布前统一处理。这样做看似在评审后额外加了工作量实际却大幅减少了后期测试阶段因为编码规范问题导致的返工。还有一个小技巧在为安全相关项目配置故障注入环境时尽量把故障场景脚本分类编号保存并和测试报告关联起来。这样无论是后续回归测试还是应对审计提问都能快速找到“当时测了什么、为什么这样测、测试结果如何”。这比在多个Excel表格间来回查找要省心得多而且在项目交接时对方团队能更快接手你的测试资产。这次大会的内容很多但关于功能安全和信息安全工具链的讨论给我留下的印象最深。工具不是万能的但没有工具支撑安全标准就只会停留在纸面上。希望这篇回顾能给正在推进安全相关嵌入式项目的同行带来一些参考。
返回列表