裸机安全与片上分析:SoC硬件级安全监控设计实战
2026/8/27 1:23:41 网站建设 项目流程

1. 思路拆解:当安全监控器“住进”芯片内部

1.1 为什么非要“裸机”安全

先说一个很多人容易混淆的概念:Bare Metal(裸机)安全,一般指的是在没有操作系统、没有完整软件栈的前提下,直接在硬件和底层固件上完成安全决策和控制。以前大家聊芯片安全,第一反应是“装个安全操作系统”“在应用层做权限管理”,但这套玩法在IoT终端、车规控制器、边缘AI推理盒上越来越吃力。原因很简单:OS本身就有攻击面,内核漏洞、驱动漏洞、恶意提权,一层一层下来,安全机制变成跷跷板,补丁追着漏洞跑。

放到SoC(System-on-Chip,系统级芯片)里,裸机安全的思路是:把安全监控逻辑做成硬件状态机或者极小的固件监控器,跑在独立的安全域里,不管主CPU上跑的是什么操作系统——是Linux也好、RTOS也好、甚至裸机应用也好——安全监控逻辑都不依赖于这些软件环境,而是直接吃芯片内部的硬件信号、总线流量、内存访问事件和异常状态。这样一来,即使主系统被攻破,攻击者也没法轻易关掉安全监控,因为那套逻辑根本不暴露在主CPU的软件接口上。

这个思路真正落地,靠的是一套叫“片上分析”(On-Chip Analytics)的机制。简单说,就是把过去放在上位机、云端或者边界网关上的行为分析能力,搬到芯片内部,用硬件单元实时采集数据、在本地做判断、必要时直接触发硬件级响应。这有什么好处?延迟低、不依赖网络、不依赖外部信任、攻击者篡改不了监控数据。

1.2 片上分析:把“遥测”这件事从软件搬到硅片上

传统SoC的遥测思路是“上报-分析-响应”,设备上的agent发日志到云端,云端跑规则引擎,发现可疑再推策略下来。这条路在面对实时性要求高的场景时不够用,尤其车里的转向控制、工业现场的伺服驱动,响应延迟要求毫秒甚至微秒级,数据兜一圈云端再回来,黄花菜都凉了。

把遥测和分析放到芯片内部后,逻辑就变成:芯片内部的性能计数器、总线追踪器、中断控制器、电源域监控器,持续把运行状态喂给一个片上分析引擎。这个引擎可以是硬件逻辑块,也可以是一个独立小核上的裸机监控固件。它实时比对当前行为与预设的安全基线,一发现异常,比如某个外设IP突然开始频繁发起DMA访问、CPU尝试访问未授权的地址空间、总线事务的时序特征偏离正态分布,就可以在几个时钟周期内触发响应动作。

这相当于给芯片配了一个“驻场保安”,而且还是带分析能力、可以现场判事的那种。外部SOC芯片和云端平台仍然可以收到告警,但不再承担实时决策的职能,决策权下沉到硅片内部。

1.3 这套方案能堵住哪些传统漏洞

我整理了一下,裸机安全加片上分析这套组合,主要解决了四类问题:

  • 固件替换型攻击:攻击者篡改启动固件,用恶意固件引导系统。裸机信任根校验保证固件签名匹配,改了就不让启动。
  • 侧信道与故障注入:攻击者通过电源毛刺、时钟干扰、激光照射等方式诱发安全逻辑跳变。片上分析引擎持续监控时钟频率、电源电压、温度异常,一旦检测到异常物理参数就锁死安全域。
  • 内核态提权后的横向移动:攻击者拿到root权限后,尝试访问安全外设、读密钥、改安全配置寄存器。裸机监控器通过总线访问控制规则,把这些访问请求挡在门外。
  • 运行时行为异常:比如勒索软件大规模读文件、某个传感器模块突然高频上报异常数据。片上分析引擎通过统计建模检测行为偏离,直接掐断相关IP的时钟或电源。

这些能力放到OS层去做,性能和隔离效果都很难达标,到了硬件层才真正有“物理级”的兜底能力。

2. 核心技术点:裸机安全与片上分析的分工体系

2.1 信任根与安全启动链

裸机安全不是凭空存在的,它需要一个信任起点。业界通用的做法是:在SoC内部放一个一次性可编程存储器(OTP/efuse),烧录根密钥的哈希值和芯片身份信息,这个OTP只能写入不能篡改,从物理层面保证信任根不可伪造。

安全启动链是这么走的:芯片上电后,处理器从Boot ROM开始执行,Boot ROM里的代码(通常只有十几KB)验证第一级引导加载器的签名。验证通过后,跳出Boot ROM,执行一级引导程序,一级引导程序再验证下一级固件,一直到把整个系统软件栈逐层验证完。这个链条的每一环,都发生在主操作系统接管系统之前,所以叫“裸机”阶段。

我见过不少团队在这个环节犯的错是:Boot ROM只验证了引导加载器的头部签名,没验证代码体;还有的验证逻辑写在通用固件里,而不是写死在ROM里,结果被一次固件升级漏洞全盘绕过了。正确的做法是:所有验证策略和密钥管理都做进ROM,片上分析引擎的启动基线也要在Boot ROM阶段就完成初始化,这样才能保证分析引擎自身在安全的上下文里启动。

2.2 裸机监控器:没有OS时的安保巡逻队

裸机监控器(Bare-Metal Monitor)是这套体系的核心执行单元。它的形态可以有三种:

  • 独立安全小核 + 固件:比如Arm的Cortex-M系安全核,跑一个极小的裸机程序,负责监控系统总线、电源管理和告警处理。
  • 硬件状态机:把监控逻辑全部用电路实现,不跑固件,适合监控逻辑比较固定的场景,响应延迟最低。
  • 混合模式:硬件状态机负责紧急熔断,小核负责策略管理。

我自己的实践是用混合模式。原因很简单:纯硬件状态机虽然快,但策略调整要改RTL代码,验证周期动辄一两个月;带小核以后,可以在不触及硬件的情况下更新监控规则,灵活性好很多。但注意,小核上绝不能跑复杂的RTOS,更不推荐上Linux——它一旦出问题,整个安全监控就失守了。裸机裸到底,最好的状态是循环轮询加中断驱动,每一行代码都简洁可控。

裸机监控器的典型职责有这么几个:

  • 周期性检查系统各安全域的健康状态,比如看门狗、电源状态、时钟频率。
  • 监听系统总线上的访问异常,对照预设的访问控制表,超限即拦截。
  • 接收片上分析引擎输出的告警事件,根据事件级别执行响应策略。
  • 管理非易失存储里的安全事件日志,把低频次的异常记录持久化,供事后取证。

2.3 片上分析引擎的核心要素

片上分析不是把软件里的贝叶斯模型硬塞进硬件,而是去适配芯片内部能天然产生的“行为传感器”。我常用的分析数据源包括:

  • 性能计数器(Performance Counter):每个CPU核甚至每个关键IP都有。能统计缓存命中率、分支预测错误率、取指周期数、总线等待周期等。
  • 总线追踪器(Bus Trace):监控AXI/AHB等片上总线的事务模式,包括读写地址分布、事务长度、突发类型、访问主从设备ID。
  • 电源域/时钟域监控:电压调节器状态、时钟锁相环锁定状态、功耗估算值。
  • 中断与异常记录:异常向量表的一级索引、中断触发频率、嵌套中断深度。

分析引擎拿到这些数据以后怎么处理?我常用的方法是“基线统计 + 阈值熔断”两层。第一层是启动阶段建立安全基线:芯片正常运行起来后,统计各个监控指标在一定时间窗口内的均值、方差、极值,作为基线存起来。第二层是运行时比对:每秒或每几百微秒刷新一次统计窗口,跟基线对照,偏差超过三个标准差就计几次异常,异常连续出现并超过阈值就触发告警。

举个例子:某个传感器控制器的正常DMA事务频率是每秒1200次左右,标准差约30次。突然某次固件被注入恶意代码,DMA频率飙到每秒5000次,这个变化远超自然波动范围,分析引擎会在几十微秒内拉高告警级别,同时通过硬件信号通知裸机监控器做出处置。

2.4 告警与响应机制的权衡

告警级别和响应动作如果不提前设计好,很容易出现两个极端:响应太激进导致系统频繁重启,响应太温和导致攻击者抓不住。我习惯把响应策略定成四级,每一级对应不同的硬件动作:

告警级别典型触发事件响应动作
记录级单次异常访问、轻微行为偏离仅写入安全事件日志,不打断系统运行
通知级连续多次越界访问、DMA频率异常发送硬件中断给主CPU,保留现场证据
限制级固件签名校验失败、安全域访问冲突切断目标外设时钟/电源,隔离可疑模块
熔断级物理攻击征兆、安全密钥被尝试非法读取整芯片复位到安全状态,禁止再次启动

这里有个容易忽略的细节:告警级别之间的延迟和阈值需要结合芯片的实际业务场景调。像工业控制类SoC,系统的DMA行为比较规律,阈值可以设紧一些;像通用应用处理器,IO场景复杂,基线统计窗口就要拉大,阈值设松一些。没有绝对通用的阈值,这也解释了为什么裸机监控器需要支持运行期规则更新。

3. 实操过程:从零搭建一个带裸机安全监控的SoC原型

3.1 顶层架构与系统框图

下面我以自己做过的RISC-V核SoC原型为例,讲一下从零搭建的完整过程,不完全是最新工艺实现,但架构思路可以直接复刻。

芯片的顶层架构大概是这样的:

  • 一个主CPU簇(RISC-V双核,支持S模式/U模式)
  • 一个安全子系统:包含一个Cortex-M3级别的安全小核、安全SRAM、OTP控制器、安全启动ROM
  • 片上总线采用AXI4主互连,所有主设备(CPU、DMA、GPU等)访问从设备时,都经安全访问控制模块做权限过滤
  • 每个关键IP旁边加一个遥测收集点,用AHB-Lite配置寄存器接口读状态
  • 一个中央片上分析引擎(Analytics Engine)挂在AXI总线上,同时有专用的硬件信号线接到各遥测点
  • 一个告警分发器:把分析引擎的告警等级编码成GPIO加中断,发到裸机监控器小核

系统级的安全策略在启动流程里分两阶段:

第一阶段,Boot ROM验证安全小核固件和主CPU引导程序。第二阶段,安全小核启动后,加载访问控制表和告警阈值表到安全SRAM,然后主CPU才会被释放运行。这套顺序保证整个系统运行的时候,安全监控已经在线。

实际搭建时要注意,主CPU和安全小核之间的通信、告警、状态同步,尽量不要通过共享内存的软件协议,而是走硬件信箱(Mailbox)加中断。原因是共享内存方式会被主CPU侧恶意代码篡改数据,硬件信箱加硬件校验则安全得多。

3.2 RTL端:安全监控器与遥测单元设计要点

安全访问控制模块(SAC)是RTL端最核心的部件。它本质上是一个挂在AXI互连上的过滤桥:

module sac_bridge #( parameter ID_WIDTH = 4, parameter ADDR_WIDTH = 32, parameter DATA_WIDTH = 64 ) ( input logic clk, input logic rst_n, // 来自总线的输入端口 AXI_Interface.Slave s_axi, // 经过过滤后的输出端口 AXI_Interface.Master m_axi, // 配置接口 input logic [31:0] cfg_addr, input logic [31:0] cfg_data, input logic cfg_wr, output logic [31:0] cfg_rdata, // 告警输出 output logic [1:0] alarm_level ); // 访问控制表,寄存器组实现 logic [3:0] access_rules [0:15]; // 主设备ID解码 logic [ID_WIDTH-1:0] master_id; assign master_id = s_axi.awid; // 地址区域匹配 logic [7:0] region_hit; integer i; always_comb begin region_hit = 8'h0; for (i = 0; i < 8; i++) begin if (s_axi.awaddr >= region_base[i] && s_axi.awaddr < region_base[i] + region_size[i]) region_hit[i] = 1'b1; end end // 访问使能判断 logic access_allowed; always_comb begin access_allowed = 1'b1; for (i = 0; i < 8; i++) begin if (region_hit[i] && !access_rules[{master_id, i[2:0]}]) access_allowed = 1'b0; end end ...

这段代码暴露了两个设计要点。一是规则存储:访问控制表里的每一个条目是“主设备ID + 目标地址区域”能否访问,这里的ID不是随便取的,必须在SoC集成时全局规划,每个主设备ID一个编号,不能复用。二是反应动作:当访问被禁止时,我建议“返回错误响应 + 记录告警 + 阻断事务”三者同时做,不要只返回错误不阻断,否则攻击者可以通过反复试探访问来推断规则表内容。

遥测单元设计上,关键是采样不干扰正常业务。我用的办法是,每个关键主设备的数据通路旁边,放一组计数器,计数器的时钟是全局时钟,但使能信号是总线事务的有效信号。计数器做成可清零可读的,裸机监控器定时通过配置总线读取。

3.3 裸机固件:主CPU上的安全监控程序

裸机监控器的固件,我一般用C语言写,编译到安全小核上。这里有一个非常重要的原则:固件里绝对不能有动态内存分配,不能有系统调用,不能有多线程切换,最好连标准库都尽量少带。逻辑越简单,越容易做静态分析和形式化验证。

一个常规监控循环的骨架长这样:

#include <stdint.h> #include "soc_regs.h" #define POLL_INTERVAL_US 100 #define ALARM_LIMIT 5 #define TELEMETRY_TIMEOUT 1000 static uint32_t baseline_dma_freq; static uint32_t baseline_cpu_bus_util; void security_monitor_init(void) { sac_load_default_rules(); analytics_set_baseline(BASELINE_DMA_FREQ); alarm_init(); mailbox_init(MAILBOX_ID_SECURE); watchdog_start(WDT_TIMEOUT_MS); } uint32_t read_telemetry(uint32_t sensor_id) { uint32_t val = 0; for (int i = 0; i < TELEMETRY_TIMEOUT; i++) { if (telemetry_fifo_ready(sensor_id)) { val = telemetry_fifo_read(sensor_id); break; } } return val; } void security_monitor_loop(void) { uint32_t dma_freq = read_telemetry(TELEMETRY_DMA_CTRL); uint32_t bus_util = read_telemetry(TELEMETRY_AXI_UTIL); if (analytics_anomaly_score(TELEMETRY_DMA_CTRL) > ALARM_LIMIT) { alarm_send(ALARM_LEVEL_LIMIT, ALARM_SRC_DMA); // 切断可疑IP的时钟 clk_gate_write(CLK_EN_CTRL_DMA_BIT, 0); } if (bus_util > baseline_cpu_bus_util * 3) { alarm_send(ALARM_LEVEL_NOTIFY, ALARM_SRC_BUS); } watchdog_kick(); }

这里我特意只写了监控逻辑没写业务调度,因为小核上跑业务调度本身就违背“最小可信计算基”的原则。如果安全性要求更高,可以把裸机程序做成完全轮询,不用任何中断——代价是响应慢一些,但逻辑推演和测试覆盖率能做到很高。

做固件验证的时候,我建议在汇编层抽查几条关键路径,因为编译器在高优化等级下可能把某些寄存器写操作重排,导致硬件控制时序错误。

3.4 仿真验证与FPGA跑通

这部分的坑比前面加起来都多,我单独划块说。

RTL级仿真阶段,我用的工具链是Verilator配合UVM验证环境。验证主要覆盖这几类场景:

  • 功能正确性:安全访问规则是否生效,合法的访问不被误拦,非法的访问必须被拦。
  • 时序特性:告警信号到硬件响应动作之间的延迟是否在指标内。
  • 边界条件:访问地址恰好落在区域边界内一个字节,会不会被误判。
  • 随机注入:随机生成各种AXI事务模式,加随机延迟,看SAC模块会不会漏拦截。

UVM环境里的一个经典场景是同时模拟主CPU侧恶意DMA引擎大流量访问敏感地址区域,然后检查分析引擎的告警延时是否低于规定值。我实际测过一个原型,未优化时告警延迟在微秒级,性能瓶颈主要在查询访问控制表的时序上,后来把规则表改成并行比较器以后,告警延迟降到了亚微秒级。

FPGA验证阶段,有一个很容易被忽视的坑:FPGA的BRAM初始化和SoC工艺里SRAM初始化行为不一致。在ASIC里,SRAM上电后状态是未知的,Boot ROM必须先把所有安全域SRAM清零,才能做后续验证。但FPGA的BRAM上电后有可能直接加载BIT文件里的初值。这会掩盖“上电乱态”的安全漏洞。我在FPGA上验证时,故意把安全SRAM的初值设成全1,然后在Boot ROM里做了一次清零过程,确认系统能正确恢复。

4. 常见问题与排查技巧实录

4.1 误报率过高怎么办

片上分析引擎最容易碰到的就是误报。嵌入式系统的IO模式本身有波动,尤其是带网络功能、带用户交互相的SoC,一个用户操作就能让总线利用率跳一个台阶。如果基线没建好,系统上线第一天就各种误报警。

我的排查顺序是:先看基线窗口是否太短,比如只用1秒统计,波动就会很大;其次看阈值设置,三个标准差听起来合理,但在实际场景里有些指标天然是重尾分布,就要改用四分位距来判断异常;最后看统计口径,确认你统计的是“健康业务下的正常波动”,而不是把启动阶段的特殊操作也算进去了。

另一个实用技巧:把分析引擎的告警分级和业务行为关联。比如中断风暴、DMA洪峰这类事件,可以先降级成“记录级”,只做日志采集,等确认是攻击行为以后,再通过裸机监控器更新阈值和策略,升级为“限制级”。这样既不影响业务上线,也能不断优化检测规则。

4.2 性能开销如何压下来

安全是有代价的,每次总线访问都做规则检查,肯定会有额外周期。我在实际项目里测过,不加SAC的AXI访问延迟是几个周期,加上SAC以后大概多2到4个周期,对于现在1GHz以上的主频来说,几十纳秒的开销省不掉,只能优化。

我的优化手段有两个。第一是“白名单快通路”:在SAC里加一组全关联的高速比较器,只匹配最常见的安全访问模式,命中的直接放行,不用走完整规则查找流程。实测命中率能到85%以上,平均延迟接近零。第二是“按域关闭监控”:对于完全不涉密的外设(比如LED控制器、蜂鸣器),可以通过配置直接关闭SAC过滤,减少热路径上的审查压力。当然,关闭之前要确保访问控制规则里这些外设本身不归属任何敏感区域。

分析引擎本身的功耗也要关注。我建议对遥测数据的采样频率做动态调节:系统负载低的时候,可以把采样频率提高,做到更细粒度的行为画像;系统负载高、本身对性能敏感的时候,降低采样频率,优先保证业务吞吐。这个动态调节逻辑放在裸机监控器里执行,因为它掌握全局状态。

4.3 调试裸机安全逻辑的三个坑

这块我踩过不少坑,挑三个最有代表性的讲。

第一个坑是安全小核的固件升级。一旦安全小核固件本身有漏洞,而且可以被人为更新,那整个信任链就崩了。很多设计把安全固件放在外部Flash里,签名校验链做得不严。我强烈建议安全固件放在内部Flash,并且硬件上做一次熔断:产品出厂后,禁止安全固件的寄存器写保护解除。真要升级,必须走带物理授权的烧录工具柜。

第二个坑是告警风暴导致安全小核假死。设计响应动作时,如果某个攻击行为持续触发告警,小核一直在处理告警就没时间做轮询了。我在裸机监控器里加了“背压机制”:同一类型告警在固定时间内最多处理N次,超出的合并处理。这样攻击者没法用高频小动作把监控器本身打瘫。

第三个坑是访问控制表和外设地址重映射冲突。如果芯片在做低功耗模式时动态映射外设地址,而安全访问控制表没有同步更新,会出现合法主设备一段时间内全部无法访问外设的故障。解决方法是让裸机监控器监听系统的地址重映射事件,在地址切换的瞬间同步更新规则表。

4.4 故障注入测试的注意事项

故障注入测试是验证裸机安全逻辑可靠性的关键步骤,包括时钟毛刺、电压跌落、电磁干扰、激光注入等。做这类测试时,我总结了几个非常实用的原则:

  • 故障注入不能只打在安全域上,要打在系统任何一个敏感模块上,包括主CPU、片上互连、存储器控制器。
  • 每轮注入后,都要重新建立信任根检查,确认Boot ROM没有被绕过,密钥没有被样本攻击。
  • 注入过程中采集的安全事件日志,要保存到带电池的非易失存储器里,否则系统一复位,取证数据就没了。
  • 运行片上分析引擎时,最好同时外接逻辑分析仪抓内部总线,事后对比分析引擎检测到的故障事件和实际注入的故障特征,看有没有漏报。

我在做时钟毛刺注入时发现,当时钟频率被拉到正常值1.5倍以上,片上分析引擎的时钟监控模块会先于所有其他模块触发熔断告警,这基本上是可靠的。但当毛刺频率很高、持续时间很窄时,时钟监控自身可能因为时序违例而失效。解决方法是采用多级冗余时钟检测,一个模块检测频率范围,一个模块专门检测边沿间隔异常,两个模块互相独立。

结尾的一点个人体会

做裸机安全加片上分析这套体系,最大的感悟是:千万别把它当成一个单纯的硬件IP或者固件模块,它更像一个贯穿芯片设计全流程的“安全运营体系”。架构阶段就要定义信任边界,RTL阶段就要把规则表、告警通道、访问控制烙进电路结构里,验证阶段又得覆盖安全和功能两条线,到了量产阶段还得考虑熔断策略和密钥管控。任何一个环节松一点,整个链条都可能在实战里被找到突破口。

我实际把类似方案跑在车规级SoC原型上以后,才真正体会到:分析引擎的基线统计、裸机监控器的响应策略、硬件访问控制表这三者之间并没有天然的主从关系,它们是需要根据业务场景一起调的“组合拳”。在一个项目里适用的阈值和策略,换一个产品形态可能完全不成立,所以不要指望一套配置吃遍天。

如果让我给一句话建议:先从最小可信计算基做起,把安全启动、片上遥测、硬件访问控制这三件事做扎实,然后再慢慢往上面叠加分析能力。安全这件事,朴实比炫技重要得多。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询