发现 STM32 防火墙的安全配置 / f" O& u6 f8 A& ]% k3 P$ W( ]4 t2 g) |前言 % k: _; b2 C# c' O- @ STM32 防火墙(Firewall)能够构建一个与其它代码隔离的带有数据存储的可信任代码区域,结合RDP、WRP以及PCROP,可用来保护安全敏感的算法。在STM32 Cube固件库参考代码里提供了几个不同的防火墙配置。那么问题来了,什么是STM32防火墙的应该使用的安全配置呢?本文以STM32参考手册为基础,以最大化安全为目标,来探索发现STM32防火墙的推荐配置。 STM32防火墙介绍 STM32防火墙保护特定代码/数据不被保护区域之外的执行所访问。代码和数据位于Flash存储器中,也可以位于SRAM1中。可选择配置的防火墙的三个保护段如下:9 q% @ L8 l* T8 s5 `9 L - 代码段(Flash), O. J7 c" H- n4 ?2 Z; q& E - 数据段(Flash) - 易失数据段(SRAM1), 可被配置为可执行 防火墙配置激活后,对受保护代码的访问必须唯一的通过调用门(Call gate)进行。防火墙外设监听AMBA总线,任何不通过调用门的访问,将导致系统重启。5 I4 U; s) m- D Figure 1 防火墙的连接 $ b8 d" X) h5 u$ W8 F5 x 不同于STM32上的ARM MPU技术,防火墙激活后,将一直保持激活状态,直至下次系统复位。 4 Q( g3 {) E* k4 B0 ~; P 防火墙的调用门* r' `/ v4 q6 ^7 V 防火墙的调用门由三个字组成,位于Flash中的代码段以及配置成非共享且可执行的SRAM1数据段,开始地址的前三个32位。* Q/ Q" ?+ N9 T `+ y0 e2 k" [ ●第1字: 虚设。总是处于关闭状态。用于保护指令预取造成的对调用门的访问。 ●第2和第3字:总是处于打开状态。 为了打开防火墙,代码必须跳到调用门的第2字执行,且第2字和第3字的执行不能被中断,否则会导致系统重启。 / ^' v8 ^; o, f1 [ 防火墙的状态图' h9 Y# C, {" ]6 y: R ?) } 防火强的配置激活后,处于关闭(Close)状态。在关闭状态下,对受保护区域的访问将被禁止。跳到防火墙的调用门处执行,则防火墙打开(open)。在防火墙打开状态下,若防火墙控制寄存器(FW_CR)的Prearm(FPA)位依然为0,跳转至非保护代码将导致系统重启。将防火墙控制寄存器的Prearm位设置成1,这时任何对非保护代码的访问将导致防火墙进入关闭(close)但激活状态。 1 c' O5 i1 S- o. w: y STM32防火墙例程* [- z( h& A# e( t2 `; | 一个STM32防火墙的实例可在CubeMX固件包里找到。例如:* V! w) F4 g: g/ ^" }% \ STM32Cube\Repository\STM32Cube_FW_L4_V1.6.0\Projects\STM32L476RG-Nucleo\Examples\FIREWALL6 {' ]0 F- J! W1 s 工程文件支持IAR和Keil开发环境,含有两个目录:: _" k2 F& s+ `( ]* M FIREWALL_VolatileData_Executable' N& B S0 K" K) i! v8 @ FIREWALL_VolatileData_Shared0 q, d( @% B0 T0 d& {) v# f 读者可使用IAR或者Keil打开这两个例子进行编译以及运行。 例程防火墙配置引出的疑问' O3 J+ f7 r8 j& }: p 例程在激活防火墙时使用了不同的配置,演示了防火墙外设的灵活性与不同的安全性,具有很好的学习用途,但是在实际应用中,为最大化安全考虑,我们究竟应该去应用哪一种配置呢?0 F; d4 Y* |( O9 l6 x. s) f. S ! E( M2 ]! K% C( L - 配置一: 仅配置保护SRAM1中的数据,且将SRAM1的数据配置成可执行且非共享。注意没有对Flash的任何地方配置保护。 配置激活 (FWDIS=0) - 配置二: 保护Flash里的代码和数据,以及SRAM1中的数据。SRAM1中的数据被配置为不可执行,但可共享。& l5 L7 w- |5 w 防火墙配置分析 SRAM1的共享 Vs. 非共享 用户手册RM0351中提到若一段SRAM1被防火墙设置为共享(VDS=1),则该区域总是可被访问,而不用去管防火墙是打开,关闭还是没有激活。 同时,SRAM1中的数据可被执行, 而不需要激活防火墙更不需要打开防火墙。换言之,共享区域其实是不在防火墙的保护之下。因此,为保护SRAM1中的敏感数据,我们应该避免使用共享配置,也就是VDS应当是0。 Figure 3 RM0351中关于防火强的易失数据段配置成可共享; z1 A% K9 X1 ? SRAM1中的执行 Vs. 非执行 用户手册RM0351中提到,若SRAM1被配置成非共享(VDS=0)且可执行(VDE=1), 防火墙的调用门序列需要先被执行。这里有几层含义,一是这段代码已经处于防火墙的保护之下;二是这段代码可被调用门中的代码调用;三是这段代码可以是调用门(参考调用门的描述)。前面我们提到防火墙打开后,保护区域之内的执行可以访问保护区域之内的代码以及数据。换言之, 这里的SRAM1执行的代码是可以访问Flash里受防火墙保护的代码和数据。SRAM1中的代码是可变 的,为避免不确定性,一般情况下我们应当避免SRAM1运行的代码访问 受保护的Flash代码和数据,也就是建议将SRAM1中配置成非执行。 Figure 4 RM0351中关于防火强的易失数据段配置成可执行. }* C; k; J+ O$ N$ z7 j 6 E; l( ^3 P) U; A6 X 是否应该配置Flash的数据段(Non-volatile data) 前面的例程配置一仅配置了SRAM1。然而用户手册RM0351中提到,Flash里的数据段未被定义,则FW_CR寄存器可在任意时刻进行修改,而不用管 防火墙是打开还是关闭。 Figure 5 RM0351中关于防火强控制寄存器的动态配置方式的描述 也就是说,防火墙相比较MPU的优势“配置有效直到系统复位”,在这种配置下不再存在了。例如在例程“配置一”里,SRAM1的代码配置成可执行非共享,受防火墙保护。然而在防火墙设置好且处于关闭状态后,我们依然可以通过保护区域之外这样的代码将该保护去掉,例如将它配置后再次改成可执行且共享。% K1 r+ `4 t4 G 读者可轻易将该代码加入到FIREWALL_VolatileData_Executable进行试验。这显然不是我们想要的安全配置, 我们应该避免这种用法。 所以,我们总是配置防火墙保护Flash中的某一数据段,使得NVDSL寄存器不为0。, V/ Z# C$ a' u0 [) B/ d' d+ d' \ 推荐的防火墙配置. p3 u [; k j+ v 综合前面的例子和分析,为最大化安全考虑,我们推荐使用防火墙 时使用以下典型配置。它配置了三个保护段,Flash中的代码和数据,SRAM1中数据;SRAM1中数据配置成不可共享且不可执行。同时要注意修改编译器链接文件将三块受保护的代码和数据分别放置到相应的下列定义的区域(Region)里。链接文件, 对IAR是.icf文件,对MDK是.sct文件。8 e% T8 t5 c' O4 @ 因为控制寄存器FW_CR,包括Prearm位、共享执行、设置,只能在防火墙打开时才能修改,因此在推荐配置下,典型的调用门代码执行序列应如下: ) O2 _, x& W2 b* m# C8 K3 Q4 o 结论 本文根据STM32参考手册, 提出了一个STM32防火墙的安全配置,可在实际STM32防火墙的案例中直接应用。也可以利用本文加深对STM32防火墙功能的理解。 ! m8 ~& x9 C0 L3 L* O 4 ~0 Q6 _' r/ Z8 d 文档下载3 k. x( q- H7 } ) w, P `! f# c, U% ^ 更多实战经验 |