menu

安全关键系统设计

markdown写起来太麻烦了, 跳转语雀:

https://www.yuque.com/jiucai-kxrf0/wyvx1y/ag125o















以下为搜索引擎收录用, 因为懒得维护博客, 无视

传统安全关键工业领域, 像是汽车, 航天, 自动化等等方向, 因为安全性是首要关注点, 所以会形成一套固定的开发流程和软件框架。 基于Linux的行业应用, 像是生活随处可见的各种电子广告牌, 点餐机, 监控摄像头, 通信设施 ,还包括各种消费电子等等,因为更多关注可拓展性和功能, 所以在开发上不会形成特别的范式。

在一个新的方向出现的时候(比如说自动驾驶, 家用机器人等领域), 因为行业没有标准, 加上为了快速完成原型, 普遍的团队都是使用Linux行业应用的方式切入。 但这些方向,用功能安全的术语来说,不乏ASIL-D的危害事件, 也就是会造成人员损伤, 因此必须要设计成安全关键系统。为了系统达到高安全性, 还是得结合传统安全关键工业领域的开发经验。 所以我想通过对比两种领域开发方式的不同,为从普通Linux行业应用的开发方式,切换到安全关键系统的开发方式上来,增加一点输入 ——— 但肯定不是说要完全的照搬, 因为对这些方向(自动驾驶, 家用机器人等), 安全性很重要, 但是功能也重要, 更需要探索一个折中的方法, 在不损失灵活性的基础上, 让系统变的更安全。

( PS: 工作经验主要做Linux行业应用为主, 对汽车行业并没有实操的经验, 输入来源于书籍和网络资料, 可能会有比较多的错误)

导图 安全关键系统

实时系统 从安全关键系统的导图上看, 实时系统主要是为了满足安全功能设计中的时序要求。 ( 这里面涉及的东西太理论了, 还没有吸收完, 随便写写,有兴趣可以看看tttech的资料和他们的书《分布式实时系统设计》 (:τ」∠)

实时操作系统 因为实时操作系统包含了框架和系统, 因此广义上我们聊实时操作系统的时候, 对其的要求并不止是说时序上的实时, 也包含对基础软件需求。 以下导图从ISO25000的角度, 随便写写安全关键系统可能的对实时操作系统的需求。 (大部分时候我们工程师差不多也就是从这个视角看问题)

工程范式 这里主要从软件视角上看工程范式,硬件视角的话, 其实也大差不差, Linux行业应用包括消费电子的硬件设计和软件设计是相对分离的, 较少整体性考虑, 更像是软件在一个已经固定下的硬件平台上自由发挥。

V模型里的架构设计是规定性的,以核心的架构师为核心。 敏捷方法中, 架构工作是描述性的, 并且分散到多个自行组织的团队中完成。 V模型在汽车等工业领域中使用的多, 因为安全性是最首要的关注点, 安全功能的架构比较关键。 在其他软件领域里, 敏捷开发更常见, 因为功能的实现是最重要的。 敏捷开发的团队更有自组织性, 有创造力, 但相对的架构工作就变得更难以掌控。

两者的差异其实从文档就可以看出来, 一个是从下到上, 一个是从上到下 就像我们使用yuque这样的工具管理文档, 每个团队会写很多记录, 但你看不到一个整体的架构性文档 但是像汽车工业, 会使用systemweaver这样的软件来统一管理需求/设计数据库

软件技术 个人觉得, 汽车工业上的 流程管理/功能安全等方法论 和 技术上的安全系统/实时系统架构设计 等是可以学习的, 但是软件技术其实不太重点, 条条框框的太多, 是通过牺牲“复杂性”, 从而达到”安全性“, 没有“软件定义”的灵活性。 但是如果你的部分子系统是可以抽离的比较干净的, 那通过复用汽车工业的软件框架, 使这部分子系统来快速达到ASIL-D的安全性等级, 也是可以的; 至于需要“软件定义”的模块, 还是需要重新探索如何更灵活满足安全设计。

设计方法V模型是安全关键行业的一种流程方法, 主要包含设计(Design), 实施(Implementation), 验证(Verification)和确认(Validation)等工作, 相比起敏捷开发, V模型更能带来 “构建稳定的产品所必需的精心设计,开发和文档编制” 。(https://wikichi.icu/wiki/V-Model_(software_development))V模型可以用在整个系统上,也可以用在某个子系统,或者软件/硬件上, 或者“功能安全”,“信息安全” 下图为“信息安全”的V流程范例下图为“功能安全”的V流程范例, 可以看到他是由一个大V+两个2个小V组成的流程比起敏捷软件开发, V模型的一部分核心区别在于V的左侧 —— 设计(Design)。本文尝试探索, 在特定工业领域以外, 更通用的更广泛的适合行业应用的V模型中的设计流程。汽车工业功能安全https://zh.wikipedia.org/wiki/ISO_26262汽车工业最典型的V模型流程就是功能安全了, 这套流程对其他安全关键的系统也很有借鉴意义, 所以我们就来看看功能安全里的设计步骤。流程识别项目(item,特定的车用系统产品),以及定义其最上层的系统功能需求。识别项目的全面风险事件(hazardous events)针对一个风险事件,定义其ASIL(可参考Part 9)针对风险事件决定其安全目标(safety goal),其中也包括风险事件的ASIL。针对汽车层级的功能安全概念(functional safety concept),定义可以确保安全目标的系统架构。将安全目标再拆解为细部的安全需求(safety requirements)(一般而言,每一个安全需求都会使用上层安全需求或安全目标的ASIL。不过因为实际情形的限制,可能会将一个安全需求拆解为数个ASIL较低,但有冗余机能的安全需求,由独立的冗余元件来实现)。安全需求会分配到各架构组件(architectural components),可能是子系统、硬件组件、软件组件(一般而言,每一个组件都需要考虑分配到安全需求的ASIL等级,依其标准和程序进行,若有多个等级,以最高的为准)依分配的安全需求以及机能需求开发架构组件,并且确认符合对应需求。支持流程ISO 26262中有定义一些在安全生命周期中在各阶段都持续进行的支持性流程,这个是整合性的流程,也提供了为了支持通用流程目标需额外考虑的事项。受控制的企业界面,可以下达目标、需求和控制方式给分散式开发中的所有供应商。明确的标示安全需求以及在生命周期中的相关管理方式。工作文档的配置管理,有正式唯一的识别方式,可以重现配置,可以建立各工作文档和配置变更之间的可追踪性正式的变更控制,包括变更影响的管理,目的是要确保识别到的缺陷已移除,在产品变更时不会导入危害。工作文档验证的规划、控制以及报告,验证可以是评审、分析及测试,也包括各来源识别到缺陷的回归分析。计划性的识别及管理在安全生命周期中,所有有助于机能安全以及安全评估持续管理的工程文档(文件)软件工具(计划使用以及实际使用的工具)的合格性审查以往开发的软件及硬件模组,要整合到目前开发ASIL等级的合格性审查用服务历史证据来证实某项目若要用在指定的ASIL等级,已有足够的安全性。相关的软件设施IQ-PMEAhttps://www.fangzhenxiu.com/post/678397/创建的步骤如下:1、使用功能网和故障网进行系统结构建模2、为故障网补充错误探测和错误响应3、确定安全目标,设定相应的控制阀,如SPFM、LFM和PMHF等4、为每一个违反安全目标的问题确定容错时间(FTT)5、为每一个错误探测确定探测时间(FDT),为每一个错误响应确定反应时间(FRT)6、记录FIT值,如在FMEDA表格7、记录具有故障或更佳的DC值并通过错误检测8、在图形编辑器中检查时间特征是否满足目标值9、复核计算基础(FIT和DC),确保完整性10、为每一个安全目标发布故障表SQTRACER标准中文版📎ISO-26262.pdf实操网上找的具体实操的案例, 有兴趣可以看看, 以深入理解安全生命周期一个简单的, 可以快速看看https://www.nxpic.org.cn/article/id-323477一个更完整的, 以理解每个步骤要做什么《基于iso26262的功能安全》https://item.jd.com/13229940.html预期功能安全https://zhuanlan.zhihu.com/p/80649486由此可见,SOTIF(中文直译为预期功能安全)的关注点是:由功能不足、或者由可合理预见的人员误用所导致的危害和风险。例如,传感系统在暴雨、积雪等天气情况下,本身并未发生故障,但是否仍能执行预期的功能。而功能安全关注于与安全相关的失效(failure),信息安全关注于与安全相关的威胁(threat)。预期功能安全的分析方法会和功能安全不太一样, 这个主要是针对算法来说的不过这个没找到什么实操说明, 以后丰富了再研究融入其他工业我尝试找了一下汽车工业以外, 其他安全关键领域的设计方法在个别行业, 用不到太复杂的安全设计, 主要用的是额外加装保护实体的方法在某些行业比如轨道交通、过程工业等,安全防护设备(如SIS)和常规控制设备(如DCS)常常是分开的。也就是说,它们在物理上是独立的实体。从系统自顶向下分解而来的安全功能,基本上都由安全防护设备来承担,而安全防护设备基本上也只承担安全功能。功能安全只针对安全防护设备,以及安全防护设备和常规控制设备的系统集成。这样的系统架构泾渭分明,非常清晰,也比较容易理解。在航天领域,会更升级到“结构化设计方法”, ”形式化建模+验证“等等http://www.cmse.gov.cn/dmt/cbw/zrht/2007n/2007ndsq_459/200808/P020200303352709108285.pdf也会看到猎鹰9这样其实没有套用所谓航天标准的产物https://ubunlog.com/en/spacex-uses-linux-and-x86-processors-on-the-falcon-9/除开技术可能不一样, 但是大体也是和汽车一样的用ISO26262这样的流程可行路径在不牺牲敏捷开发持续迭代的特性下, 较为轻量的引入V流程中的部分阶段 (主要是安全设计完整引入就算了, 在一年一代车+OTA的背景下, 连汽车工业自己都在淘汰通过对iso26262的学习,我觉得一个可行的路径, 就是把”设计“ 和 ”确认/验证“ 都当成一个程序来维护。就好像敏捷开发中的开发是一个圆圈, 那我们的改进, 是可以把设计当一个圆圈 + 开发一个圆圈 + 测试一个圆圈, 通过伪代码/代码,在线文档/管理工具, 让死板的V流程更灵活但在环的流程,就好像敏捷开发依赖于devops, 设计的在环依赖于持续的追踪和监控能力, 不过就不在这里谈论展开了。预期功能安全主要是针对算法的TODO普通功能是沿用敏捷开发 or 引入部分V模型? 规定性的架构设计是否有必要?TODO 功能安全流程总体流程管理传统流程管理工具, teambition/aone等项目定义语雀等在线文档工具, 需要人为系统化组织危险分析和风险评估功能安全概念产品开发 - 硬件设计TODO, 建模/仿真产品开发 - 软件设计TODO, 建模/仿真/软件框架 安全确认TODO, 非本文关心其实这里的难点, 还是在于引入 ”经济上可承受的连续安全分析方法“, 在敏捷开发过程中持续保证安全, 不能简单套用ISO26262, 但我们开始不用想那么多, 先引入FMEA, 能提升一点点安全性也是好的至于软件设计/硬件设计, TODO安全设计涵盖危险分析/风险评估 危险分析和风险评估的第一步是情形分析和危险识别,即通过相关的情况分析将产品 存在的风险识别出来。这就要考虑可能引发危险的操作环境和操作模式,并且要考虑在正确 使用时和可预见的误使用时的情况。基于这样的考虑,我们应该通过大量的技术来系统分析, 注意以下一些方面: 1. 准备一个用来进行评估的操作情况清单2. 系统的确定清单上的危险。主要可以通过诸如:头脑风暴,检查列表,历史记录, FMEA,产品矩阵,以及相关的领域研究等技术手段进行。3. 风险应该用在车辆上可以被观察到的条件或影响来进行定义或描述 4. 在相关操作条件和操作模式下危险事件的影响应该被明确说明。如:车辆电源系统 故障可能导致丧失引擎动力,丧失转向的电动助力以及前大灯照明。 5. 如果在风险识别中识别出的风险超出了 ISO26262 的要求范围,则需给出合适的相应 措施。当然,超出 ISO26262 的风险可以不必分类分级。 完成风险的识别之后,就要对这些风险进行适当的分级,以便设定相应的安全目标,并 按照不同的风险等级来采取合理的措施加以避免。 风险的分类主要是通过 3 个指标来考量,即:危险发生时导致的伤害的严重性、在操作 条件下暴露于危险当中的可能性(危险所在工况的发生概率)、危险的可控性。风险分析对工具的要求就是需要记录所有风险 + 给风险分级(具体怎么分级的逻辑请看ISO-26262)功能安全概念需要能管理以下的组织如何从risk到safery goal到functional safety requirement, 主要通过FMEA/FTA等分析方式所以除了要记录层次结构, 最好还能直接集成FMEA这样的安全分析方法可行路径主要分两个流程一个是使用fema的方法事前分析可能的风险 和 对应的安全处理措施, 使用FTA事后分析出现的问题和对应安全处理措施一个是把fema/fta分析后的结果导入成功能安全的文档FEMA策划与准备:识别项目,了解项目计划,定义FMEA的边界,明确FMEA的分析过程,并填写FMEA的表格的第一步栏。结构分析:首先分析产品项目的过程,针对每个过程划分过程步骤或按工站划分,再对每个步骤识别出4M要素(人、机、料、环)。使用结构树的方式进行。功能分析:可以使用功能网络、功能书、功能矩阵等方法分析。进行功能分析前,需要了解要求、产品特性和过程特性。失效分析:主要从过程步骤开始分析,过程步骤的功能失效就是失效模式;而4M要素的失效,即是失效起因;分析失效模式的发生,产生的后果,就是失效影响。风险分析:基于现有的控制手段,对第四步识别出来的风险点进行评分和判定。从严重度、频度和探测度进行评分。优化改进:基于第五步评分结果和措施优先级,制定改进优化措施。结果文件化,输出FMEA表格FTA (1)对所选定的系统作必要的分析,确切了解系统的组成及各项操作的内容,熟悉其正常的作业图; (2)对系统的故障进行定义,对预计可能发生的故障、过去发生过的故障事例作广泛的调查; (3)仔细分析各种故障的形成原因,如设计、制造、装配、运行、环境条件、人为因素等; (4)收集各故障发生的概率数据; (5)选定系统可能发生的最不希望发生的故障状态作为顶事件,画出故障逻辑图; (6)对敌障树作定性分析,确定系统的故障模式; (7)对故障树进行定量计算,计算出顶事件发生概率、各底事件的结构重要度、概率重要度、关键重要度等可靠性指标。更多见:https://www.eet-china.com/mp/a61397.html因为没有现成软件, 所以只能第一步 fmea我们可以通过excel来做, fta也有一些工具第二步 人工从fmeal翻译到功能安全需求的结构, 来指导软件设计, 如果没有软件设计就先直接跳到开发样例功能安全我们这样相当是从0搭起, 所以实践过程中一定多看ISO-26262, 看看有没有能需要拿来的, 逐渐完善大框架(内部)

本文介绍可以进行形式化验证的基于状态机的程序范式, 比如如果应用程序逻辑不太复杂, 可以直接套用范式, 就可以以较低的成本实现可靠程序。

写一个状态机程序 首先我们虚拟一个现实世界的需求场景, 要做一个多节点时间管理的服务, 比如如下图的一个结构(链接)

大概的需求可以列为以下几条:

  1. 主控节点“AM”, 辅节点”BM“, 子节点“set(SEN)”
  2. 所有节点默认都没有初始时间, 系统初始化时间由“AM”从外部”NET“获取
  3. 主控节点“AM” 可向子节点“set(SEN)” 同步时间, 如果“AM“进入”INVALID”状态, “BM”要负责控制同步时间
  4. 仅在所有节点(MM and BM)进入 “STOP” 状态时候可以进行 “BIG” 时间同步, 其他时间可以进行“LITTLE” 同步, 时间差如果大于1s, 必须进行“BIG” 时间同步

下面状态机去实现这个程序: https://github.com/wzyy2/my-studys/blob/master/0-model-checking/app/main.cpp

上面这段c代码各种状态,各种依赖, 我们也没办法确定这个程序的逻辑完备性, 所以下面做形式化验证来确认。 为状态机程序做形式化验证 流程:

针对我们刚刚实现的状态机程序, 用TLA+做一个建模(VSCODE装TLA+插件就可以执行) https://github.com/wzyy2/my-studys/blob/master/0-model-checking/tla/TimeSync.pluscal

针对这个状态机, 我们加入一些验证规则: 可恢复性:

  • 状态随意切换,最后可以正常退出

时间差:

  • AM节点start, {AM, BM, SEN}时间差小于25个tick
  • AM节点!start 后, {BM, SEN}时间差小于25个tick

因为我们设置的状态机逻辑比较简单, 最后验证没有错误。

如果以后其他状态有更多的逻辑加入, 只要维护模型, 就可以验证新加入逻辑的正确性。

其他办法保证软件逻辑的正确性? 单元测试 形式化验证是个很重的过程,等于是重复编程, 而且最终效果也是取决于验证规则的编写。 在本文的写作过程中, 我感觉到TLA+其实就是基于断言的测试用例, 在实际工程直接针对不同范式准备c++的测试用例模板覆盖就可以, 没必要和用专门的语言形式化验证。 半形式化验证 另外一种实际工业生产中用的比较多的办法, 是半形式化的分析/验证, 比如说功能安全里的流程等, 举个例子: https://zhuanlan.zhihu.com/p/444381688, 这样的一个文档其实也可以保证程序逻辑的相对正确性。 定义: 形式化(formal):在完备数学概念基础上,采用具有确定语义定义并有严格语法的语言表达的规范风格。 半形式化(semiformal):采用具有确定语义定义并有严格语法的语言表达的规范风格。 非形式化(informal):采用自然语言表达的规范风格。

非形式化验证 个人观点: 完全非形式化的文档对于“Build a Safety-critical Real-time System“的帮助非常有限。 像是常见的”XX安全功能需求/定义“这样的文档:

  1. 没描述目标系统的结构 a. 不是简单的架构堆叠, 需要有接口, 而且程序严格按接口实现
  2. 没有描述技术功能实现的逻辑 a. 比如说一个监控报警项, 信号是怎么从目标系统出来的, 是怎么观测的, 针对报警做出反应行为是怎么样工作的 导致只有实际编写代码的人才能弄懂里面的细节, 其他人仅仅阅读文档无法进行分析和验证, 无法进行专业技术上的review。

(半形式化不了可能是因为程序已经走样了~

其他程序范式的验证? TODO: 状态机可以靠穷举状态验证, 那其他程序范式的验证思路?

结束 上面通过可进行形式化验证的程序范式, 保证了程序组件逻辑的确定性, 但这还不足以保证整个程序的安全, 后面我们会再针对程序内调用的外部接口做拆解。

(本篇只是记录自己的想法, 没干货) 感觉最近脑子有点开窍, 稍微领悟到了点要用Complexity Reduction的思维去解决现实复杂问题, 要收敛复杂度。 WHAT 在我们所能查阅的资料文献里, system的面向场景都是被抽象成非常简单的描述, 也可因此“Build a Safety-critical Real-time System”并不复杂, 只需要解决单一问题。 但在实际工业中, 是要先解决场景的问题, 所以往往最重要的目标是完成system需要的功能, “Safety-critical Real-time”是次要目标, 由此把很难说服采用简单化系统来解决问题, 系统问题一定是复杂的。

HOW 解决复杂问题的思路有很多, 我的想法是使用“Separation of concerns”的方法去构建安全关键实时系统。 偷懒拿一张傅立叶变换的图做解释:

我们观测到复杂问题就是最前面的红线, 没有规律。 但是如果按照“Separation of concerns”的思路讲大问题明确为N个小问题, 这步就像是做了傅立叶变换, N个小问题就像提取出的各个频率的曲线, 规律就清晰起来。

Difference 虚的讲了一堆 ———— “Separation of concerns” 用在设计软件上分层分模块可以理解, 但解问题思路到底怎么做? 和流程导向的区别 在我的想法里, 其实就是区别于用”流程分层”的方式 or 其他方式, 还是用”组成分类” 的方法。

比如说分析/验证和测试都是属于“测试”的范畴。 按”流程分层”的思路, 我们会先有个测试团队, 测试团队去研究这个流程要做什么,按照前人的经验, 比如说什么功能安全流程, 然后引入分析/验证和测试。 按”组成分类” 的方法, 我们是先关注要解决组件可靠性这个问题。 然后发现需要对逻辑进行验证, 需要对代码进行测试 。 然后把”针对这一模块的验证/测试“加入”测试的流程“。

和问题导向的区别 我们日常中还有一种开发方式就也是关注问题的, 就是问题导向 : 所谓的不停的测试, 敏捷开发, 有bug解bug, 关注bug率。 关注点分离又和他有什么区别? 区别在于, 关注点分离的对象是“关注点”, 是可以“区分”的特定目标 ———— 这样才能收敛大的问题。

拿一个程序CPU资源不足导致卡顿作为例子:

和正向设计的区别 正向设计就像是一个正确的废话。 实践中我感觉最大的问题在于: ● 找不到足有够开发经验的工程师 ○ 新方向的经验在开发过程中积累 ● 没有成熟的基础模板 ○ 有上下游依赖关系的组件, 只能串行开发而不是并行开发, 这样的开发速度基本是不可接受的

分离关注点虽然也是近似正向设计, 但区别在“拟合”设计, 而不是直接“描述”。

思路 下面用导图记录下来在我关注的技术领域上(完整系统涉及到的知识点太多), 构建安全关键系统的思路, 以后再慢慢深入每个单点拆解。

现在这个导图只是当下能认识到的问题, 希望能尽量在后续的实验中丰富枝条 ———— 不过如果过长的话, 那就证明关注点分离这个方法在这条链上不适用, 需要换一种方法。