2. 固件基础

在固件回滚保护系统化训练中,第一步不是写保护逻辑,而是把“固件”这个对象本身看清楚。很多回滚失败、变砖、校验绕过的问题,根源都在于对固件与软件边界、存储介质特性、启动链路和固件类型理解不清。本节从工程视角梳理固件基础,为后续回滚保护设计建立共同语言。

一、固件与软件:不是“更底层的软件”这么简单

软件通常指运行在操作系统之上的应用程序或服务,依赖操作系统提供的进程、文件、网络、内存管理等抽象;固件则是嵌入在硬件设备中、直接面向处理器和外设的底层程序,往往在操作系统启动之前就已运行,甚至设备根本没有通用操作系统。固件与硬件耦合度高,生命周期长,升级频率低,一旦损坏可能导致设备无法启动。

从回滚保护角度看,二者关键差异体现在四个方面:

  • 运行位置:软件运行在 OS 之上;固件运行在裸机、RTOS 或引导阶段,直接操作寄存器、时钟、Flash 控制器。
  • 更新方式:软件可热更新、灰度发布;固件通常需要重启、进入 Bootloader 或专用升级模式,更新过程本身具有风险。
  • 失败后果:软件崩溃可重启进程;固件损坏可能导致设备无法进入升级模式,即“变砖”。
  • 回滚粒度:软件回滚可只回退某个模块;固件回滚往往涉及整镜像、分区表、引导参数,必须整体一致。
回滚保护的核心对象是“可启动的固件镜像集合”,而不是单个可执行文件。设计时必须把 Bootloader、分区表、主固件、配置区视为一个整体版本。

二、固件存储介质:NOR、NAND、eMMC 与 OTP

固件存放在哪里,直接决定了回滚保护能怎么做。常见介质包括:

介质 典型容量 特点 回滚保护关注点
NOR Flash 1MB~64MB 支持 XIP,随机读快,可字节寻址 适合存放 Bootloader,需防写保护与校验
NAND Flash 128MB~数GB 容量大、成本低,存在坏块与位翻转 需 ECC、坏块管理,回滚镜像需冗余存储
eMMC / UFS 4GB~数百GB 带控制器,支持分区与磨损均衡 需关注 RPMB、分区只读属性与安全启动
OTP / eFuse 几十字节~几KB 一次性可编程,不可逆 用于存储版本下限、密钥哈希、回滚计数器

其中 OTP/eFuse 是回滚保护的关键:一旦把“最低允许版本”写入 eFuse,低版本固件即使完整也会被拒绝启动。这比单纯在 Flash 中写标志位更难被降级攻击绕过。

三、启动流程:从复位向量到应用固件

典型嵌入式设备启动链路如下:上电复位后,CPU 从固定地址取复位向量,执行片内 BootROM;BootROM 根据启动引脚或 eFuse 配置选择启动介质,加载一级 Bootloader;一级 Bootloader 初始化时钟、DDR、Flash 控制器,再加载二级 Bootloader;二级 Bootloader 校验并加载主固件;主固件初始化外设后进入操作系统或应用逻辑。

回滚保护必须嵌入这条链路的每一个“交接点”。如果只在应用层校验版本,攻击者可以替换 Bootloader 或跳过校验。正确做法是在 BootROM 之后的每一级加载前,都验证下一级镜像的签名、哈希和版本号,并检查回滚计数器。

固件启动链路与回滚校验点 BootROM 复位向量 / 启动介质选择 一级 Bootloader 时钟 / DDR / Flash 初始化 二级 Bootloader 加载并校验主固件 主固件 / OS 应用逻辑与业务功能 运行态 设备正常工作 校验点 1 签名 + 哈希 + 版本下限 校验点 2 回滚计数器比对 校验点 3 分区表与配置一致性 回滚保护关键存储区 eFuse:最低版本 / 密钥哈希 Flash:A/B 双镜像分区 RPMB:回滚计数器 OTP:启动配置

四、常见固件类型与回滚策略差异

不同固件类型在回滚保护上的要求差异很大,常见分类如下:

  • Bootloader 固件:负责启动链,通常只允许升级不允许回滚,或回滚必须与主固件版本严格匹配。
  • 主应用固件:设备功能主体,支持 A/B 分区回滚,是回滚保护的主要对象。
  • 通信模组固件:如 Wi-Fi、蜂窝模组,常由模组厂商提供,回滚需考虑与主控固件的兼容矩阵。
  • 安全固件:负责密钥管理、安全启动,通常禁止回滚,或回滚需重新认证。
  • 配置/参数固件:如校准数据、设备树,回滚时需与固件版本绑定,避免参数与代码不匹配。
工程建议:为每一类固件定义独立的“可回滚等级”。Bootloader 和安全固件设为不可回滚或仅限同版本回滚;主应用固件允许回滚到上一个已签名版本;配置区随主固件一起回滚。

五、案例与误区复盘

某工业网关在 OTA 升级后出现启动失败。排查发现:新固件写入 B 分区成功,但 Bootloader 中的回滚计数器未同步更新,导致设备重启后仍尝试从 A 分区启动旧版本,而旧版本已被标记为“低于最低允许版本”,最终进入恢复模式。问题根因是把“镜像写入成功”等同于“回滚保护完成”,忽略了计数器与分区状态的原子更新。

常见误区还包括:

  1. 只在应用层做版本校验,Bootloader 不校验,攻击者可替换引导镜像。
  2. 把回滚标志位放在普通 Flash 分区,未做写保护,可被擦除绕过。
  3. 忽略 NAND 坏块与位翻转,回滚镜像未做冗余和 ECC,导致校验失败。
  4. A/B 分区切换时未使用原子操作,掉电后分区状态不一致。
# 典型回滚保护校验伪代码
if verify_signature(next_image) != OK:
    reject("签名校验失败")
if next_image.version < efuse.min_version:
    reject("低于最低允许版本")
if next_image.version < rpmb.rollback_counter:
    reject("回滚计数器拒绝降级")
commit_update_atomically(next_image, rpmb.rollback_counter)

理解固件与软件的区别、存储介质特性、启动链路和固件类型,是设计回滚保护的前提。只有把校验点嵌入每一级启动交接,并让版本下限、回滚计数器与镜像状态原子一致,回滚保护才真正可靠。