2. 固件基础
在固件回滚保护系统化训练中,第一步不是写保护逻辑,而是把“固件”这个对象本身看清楚。很多回滚失败、变砖、校验绕过的问题,根源都在于对固件与软件边界、存储介质特性、启动链路和固件类型理解不清。本节从工程视角梳理固件基础,为后续回滚保护设计建立共同语言。
一、固件与软件:不是“更底层的软件”这么简单
软件通常指运行在操作系统之上的应用程序或服务,依赖操作系统提供的进程、文件、网络、内存管理等抽象;固件则是嵌入在硬件设备中、直接面向处理器和外设的底层程序,往往在操作系统启动之前就已运行,甚至设备根本没有通用操作系统。固件与硬件耦合度高,生命周期长,升级频率低,一旦损坏可能导致设备无法启动。
从回滚保护角度看,二者关键差异体现在四个方面:
- 运行位置:软件运行在 OS 之上;固件运行在裸机、RTOS 或引导阶段,直接操作寄存器、时钟、Flash 控制器。
- 更新方式:软件可热更新、灰度发布;固件通常需要重启、进入 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 之后的每一级加载前,都验证下一级镜像的签名、哈希和版本号,并检查回滚计数器。
四、常见固件类型与回滚策略差异
不同固件类型在回滚保护上的要求差异很大,常见分类如下:
- Bootloader 固件:负责启动链,通常只允许升级不允许回滚,或回滚必须与主固件版本严格匹配。
- 主应用固件:设备功能主体,支持 A/B 分区回滚,是回滚保护的主要对象。
- 通信模组固件:如 Wi-Fi、蜂窝模组,常由模组厂商提供,回滚需考虑与主控固件的兼容矩阵。
- 安全固件:负责密钥管理、安全启动,通常禁止回滚,或回滚需重新认证。
- 配置/参数固件:如校准数据、设备树,回滚时需与固件版本绑定,避免参数与代码不匹配。
五、案例与误区复盘
某工业网关在 OTA 升级后出现启动失败。排查发现:新固件写入 B 分区成功,但 Bootloader 中的回滚计数器未同步更新,导致设备重启后仍尝试从 A 分区启动旧版本,而旧版本已被标记为“低于最低允许版本”,最终进入恢复模式。问题根因是把“镜像写入成功”等同于“回滚保护完成”,忽略了计数器与分区状态的原子更新。
常见误区还包括:
- 只在应用层做版本校验,Bootloader 不校验,攻击者可替换引导镜像。
- 把回滚标志位放在普通 Flash 分区,未做写保护,可被擦除绕过。
- 忽略 NAND 坏块与位翻转,回滚镜像未做冗余和 ECC,导致校验失败。
- 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)
理解固件与软件的区别、存储介质特性、启动链路和固件类型,是设计回滚保护的前提。只有把校验点嵌入每一级启动交接,并让版本下限、回滚计数器与镜像状态原子一致,回滚保护才真正可靠。