69、Armv8-M TrustZone安全机制深入解析

Armv8-M TrustZone安全机制深入解析

1. SAU寄存器与概念概述

安全属性单元(SAU)包含多个可编程寄存器,这些寄存器位于系统控制空间(SCS),仅能从安全特权状态访问,且对SAU寄存器的访问始终为32位。SAU寄存器的概要如下表所示:
| 地址 | 寄存器 | CMSIS - CORE符号 | 全名 |
| ---- | ---- | ---- | ---- |
| 0xE000EDD0 | SAU_CTRL | SAU->CTRL | SAU控制寄存器 |
| 0xE000EDD4 | SAU_TYPE | SAU->TYPE | SAU类型寄存器 |
| 0xE000EDD8 | SAU_RNR | SAU->RNR | SAU区域编号寄存器 |
| 0xE000EDDC | SAU_RBAR | SAU->RBAR | SAU区域基地址寄存器 |
| 0xE000EDE0 | SAU_RLAR | SAU->RLAR | SAU区域限制地址寄存器 |
| 0xE000EDE4 | SAU_SFSR | SAU->SFSR | SAU安全故障状态寄存器 |
| 0xE000EDE8 | SAU_SFAR | SAU->SFAR | SAU安全故障地址寄存器 |

SAU通过基地址(起始地址)和限制地址(结束地址)来定义内存区域,其粒度为32字节,工作方式与MPU类似。Cortex - M23和Cortex - M33处理器中的SAU可以有0、4或8个SAU区域。在支持TrustZone的Armv8 - M处理器中,即使SAU被配置为零个区域,SAU仍然可用,此时内存分区将完全由IDAUs处理,具体的内存分区由设计IDAUs的芯片设计师定义。

SAU地址查找行为如下:
- 若SAU启用,且地址与SAU区域匹配,结果将基于地址比较器的设置,为非安全或安全非安全可调用(NSC)。
- 若SAU启用,但地址与任何SAU区域都不匹配,结果为安全。
- 若SAU禁用,且SAU控制寄存器中的ALLNS(全非安全)位被置位,结果为非安全(即内存映射完全由IDAUs决定)。
- 若SAU禁用,且SAU控制寄存器中的ALLNS位为零,结果为安全,这是复位后的默认设置。

在执行TT(测试目标)指令时,当SAU区域与TT检查输入的地址匹配时,匹配的SAU区域的编号将作为TT执行结果的一部分报告。

同时,在使用SAU进行地址查找时,IDAUs也会并行进行地址查找,两者的查找结果会进行合并。对于超低功耗应用且硅面积小的芯片,可以使用IDAUs进行地址分区,并使用无区域比较器的SAU。在这种情况下,处理TrustZone初始化的安全软件只需将SAU控制寄存器中的ALLNS位设置为1,这样安全分区就仅由IDAUs处理。

2. SAU寄存器详细介绍

2.1 SAU控制寄存器

SAU控制寄存器提供SAU的全局使能控制位。即使SAU被配置为零个区域,该寄存器仍然存在。默认情况下,SAU禁用,ALLNS位清零,这意味着整个内存映射默认是安全的。在设置SAU控制寄存器中的ENABLE位之前,初始化SAU的软件必须清除未使用SAU区域的“使能”位,因为复位后每个SAU区域的单个使能位是未定义的。其详细信息如下表:
| 位 | 名称 | 类型 | 复位值 | 描述 |
| ---- | ---- | ---- | ---- | ---- |
| 31:2 | Reserved | – | 0 | 保留 |
| 1 | ALLNS | R/W | 0 | 全非安全。置为1时,SAU查找结果始终为非安全;否则,结果为安全。 |
| 0 | ENABLE | R/W | 0 | 置为1时,启用SAU。若SAU区域为零,此位固定为0。 |

2.2 SAU类型寄存器

SAU类型寄存器详细说明了SAU中实现的区域数量,具体信息如下表:
| 位 | 名称 | 类型 | 复位值 | 描述 |
| ---- | ---- | ---- | ---- | ---- |
| 31:8 | Reserved | – | 0 | 保留 |
| 7:0 | SREGION | RO | 0 | 实现的SAU区域数量(0、4或8)。 |

2.3 SAU区域编号寄存器

SAU区域编号寄存器用于选择要配置的SAU区域,如下表所示:
| 位 | 名称 | 类型 | 复位值 | 描述 |
| ---- | ---- | ---- | ---- | ---- |
| 31:8 | Reserved | – | 0 | 保留 |
| 7:0 | REGION | R/W | 0 | 选择当前由SAU_RBAR和SAU_RLAR寄存器访问的区域 |

2.4 SAU区域基地址寄存器

SAU区域基地址寄存器详细说明了由SAU区域编号寄存器当前选择的SAU区域的起始地址,详情如下表:
| 位 | 名称 | 类型 | 复位值 | 描述 |
| ---- | ---- | ---- | ---- | ---- |
| 31:5 | BADDR | R/W | – | 区域基(起始)地址 |
| 4:0 | Reserved | – | 0 | 保留。读为零,写操作被忽略。 |

2.5 SAU区域限制地址寄存器

SAU区域限制地址寄存器详细说明了由SAU区域编号寄存器当前选择的SAU区域的限制地址。SAU区域的结束地址包含此寄存器中设置的限制地址,SAU区域结束地址的最低5位会自动填充为0x1F,因此32字节粒度的最后一个字节也包含在SAU区域中。具体信息如下表:
| 位 | 名称 | 类型 | 复位值 | 描述 |
| ---- | ---- | ---- | ---- | ---- |
| 31:5 | LADDR | R/W | – | 区域限制(结束)地址 |
| 4:2 | Reserved | – | 0 | 保留。读为零,写操作被忽略。 |
| 1 | NSC | R/W | – | 非安全可调用。若此位为1,SAU区域匹配将返回安全非安全可调用(NSC)内存类型;否则,返回非安全内存类型。 |
| 0 | ENABLE | R/W | – | 置为1时,启用SAU区域;否则,区域禁用。 |

2.6 安全故障状态寄存器(SFSR)和安全故障地址寄存器(SFAR)

SFSR和SFAR寄存器在Armv8 - M主线处理器(如Cortex - M33)中可用,但在Armv8 - M基线处理器(即Cortex - M23)中不可用。这些寄存器允许安全故障异常处理程序报告故障异常的信息,并可能让故障异常处理程序处理该问题,获取的信息也可在调试会话中帮助软件开发人员理解软件操作期间出现的任何问题。

3. 非安全软件调用安全API

“TrustZone for Armv8 - M”的关键特性之一是允许安全和非安全软件之间进行直接函数调用,这使得安全固件能够提供一系列服务,如加密操作的API、安全存储以及建立与云服务的安全物联网连接的API。

为确保设计安全,引入了一系列硬件特性来防止非法状态转换。非安全软件调用安全API/函数时,必须满足以下两个条件:
- 安全API的第一条指令是SG(安全网关)指令。
- SG指令位于标记为非安全可调用的内存区域。

若不满足这些条件,将检测到安全违规,并触发安全故障或硬故障异常来处理错误,因此无法分支到安全函数的中间并绕过安全检查。

当非安全代码调用安全API时,非安全代码分支到安全API的安全地址位置称为入口点。安全固件中可以有任意数量的入口点,每个NSC区域可以有多个入口点,内存映射中也可以有多个NSC区域。由于非安全软件调用安全API时使用普通的分支和链接指令(如BL或BLX指令),因此非安全软件项目不需要工具链的任何特殊编译支持即可与安全软件配合使用。

执行SG指令时,处理器仍处于非安全状态,只有在SG指令成功执行后,处理器才进入安全状态。非安全软件开发人员在调试会话中可以看到分支到入口点的执行情况,虽然安全入口点的地址对他们可见,但由于没有安全调试权限,无法访问安全内存中的内容,他们能看到的唯一安全固件信息是入口点的地址,这些地址包含在安全软件开发人员提供的导出库中。

引入非安全可调用(NSC)内存属性是为了防止安全软件中的二进制数据(包含与SG指令操作码匹配的模式)被黑客滥用。通过确保只有入口点位于标记为NSC的内存中,可以消除意外入口点的风险。

在安全API结束时的函数返回部分,应使用“BXNS LR”指令而不是通常的“BX LR”指令。Armv8 - M引入了“BXNS ”和“BLXNS ”指令,当地址寄存器(由 指定)的第0位为0时,处理器可以从安全状态切换到非安全状态。执行SG指令时,处理器会根据之前的状态自动设置链接寄存器(LR)的第0位:
- 若在执行SG指令之前处理器处于非安全状态,将LR的第0位清零。
- 若在执行SG指令之前处理器处于安全状态,将LR的第0位置为1。

在安全API结束时进行函数返回,若LR的第0位为0(在函数入口处由SG清零),处理器知道必须返回非安全世界;若返回安全地址,将触发故障异常,这可以检测并防止黑客使用指向安全程序位置的虚假返回地址调用安全API。若同一安全API被另一个安全函数调用,函数入口处的SG指令执行会将LR的第0位置为1,在安全API结束时,使用LR值进行函数返回,处理器知道将返回安全程序位置,这种安排允许安全API被非安全或安全代码使用。

为帮助软件开发人员在C/C++中创建安全API,Cortex - M安全扩展(CMSE)定义了一个C函数属性“cmse_nonsecure_entry”。

4. 安全代码调用非安全函数

TrustZone for Armv8 - M允许安全软件调用非安全函数,这在以下情况下很有用:
- 安全世界中的中间件软件组件需要访问非安全世界中的外设驱动程序以访问特定外设功能。
- 安全固件需要访问非安全世界中的错误处理函数(即回调函数),回调机制允许安全软件在发生错误时通知非安全软件。例如,一个为非安全软件组件处理后台内存复制服务的安全API可以使用安全DMA控制器执行操作,安全软件可以使用回调机制在DMA操作出错时通知非安全软件。

安全软件调用非安全函数时,应使用BLXNS指令。与使用BXNS指令类似,保存分支目标地址的寄存器的第0位用于指示被调用函数的安全状态:若该位为0,处理器在分支时必须切换到非安全状态;若该位为1,分支目标是安全函数。

分支到非安全函数时,BLXNS指令会将返回地址和部分xPSR保存到安全栈,并将LR更新为一个特殊值FNC_RETURN(即函数返回)。PSR(程序状态寄存器)中的部分信息也会保存到安全栈,在返回安全状态时使用。FNC_RETURN的值为0xFEFFFFFF或0xFEFFFFFE,具体如下表:
| 位 | 描述 |
| ---- | ---- |
| 31:24 | PREFIX—必须为0xFE |
| 23:1 | Reserved—这些位必须为“1” |
| 0 | S (Secure)—指示调用代码的安全状态。0表示函数从非安全状态调用;1表示函数从安全状态调用。此位通常为1,因为FNC_RETURN机制用于安全代码调用非安全世界中的函数,但在某些函数链情况中,此位可能被SG指令清零,函数返回机制在处理分支到FNC_RETURN时会忽略此位。 |

在非安全函数结束时,返回操作(如“BX LR”)将FNC_RETURN值加载到程序计数器(PC),触发从安全栈中弹出真正的返回地址,并使用之前压入安全栈的部分PSR进行完整性检查。使用FNC_RETURN可以向非安全世界隐藏安全程序地址,避免任何秘密信息泄露,同时防止非安全软件修改存储在安全栈中的安全返回地址。

若处理器在调用非安全API时处于安全处理模式,程序状态寄存器的一部分(IPSR的值)会保存到安全主栈,IPSR的值会切换为1以掩盖调用的安全处理程序的身份。当非安全API结束并返回安全世界时,会进行完整性检查以确保处理器的模式未改变,调用非安全API时改为1的IPSR会恢复为之前的值。

5. BXNS和BLXNS指令相关信息

BXNS和BLXNS指令在实现TrustZone的Armv8 - M处理器中可用,且只能由安全软件使用。当处理器处于非安全状态时,任何执行这些指令的尝试都会被视为未定义指令错误,并触发硬故障或使用故障异常。在C/C++编程中,使用CMSE功能创建安全API或调用非安全函数时,无需使用内联汇编器手动插入这些指令,因为C编译器会生成这些指令。其行为如下表所示:
| 执行状态(指令) | 条件 | 结果 |
| ---- | ---- | ---- |
| 安全状态(BX, BLX) | 地址的LSB为1 | 分支到安全状态的地址 |
| 安全状态(BX, BLX) | 地址的LSB为0 | 导致硬故障/使用故障 |
| 安全状态(BXNS, BLXNS) | 地址的LSB为1 | 分支到安全状态的地址 |
| 安全状态(BXNS, BLXNS) | 地址的LSB为0 | 分支到非安全状态的地址 |
| 非安全状态(BX, BLX) | 地址的LSB为1 | 分支到安全或非安全地址 |
| 非安全状态(BX, BLX) | 地址的LSB为0 | 导致硬故障/使用故障 |
| 非安全状态(BXNS, BLXNS) | BXNS, BLXNS不支持 | 导致硬故障/使用故障 |

6. 安全状态转换与特权级别变化

由函数调用或函数返回引起的安全状态转换可能会导致处理器的特权级别发生变化,这是因为处理器CONTROL寄存器中的nPRIV位在安全状态之间是分库存储的。

由函数调用或函数返回引起的特权级别变化仅在处理器处于线程模式时发生。若处理器处于处理模式,在跨域函数调用/返回时,处理器将保持在特权级别,原因如下:
- 中断程序状态寄存器(IPSR)在安全和非安全世界之间共享。
- 架构定义规定处理器在处理模式下必须处于特权状态。

由于Armv8 - M架构的定义方式,当安全软件库中的安全API被非安全异常处理程序调用时,将以特权访问级别执行。若需要将安全API的访问权限限制为非特权级别,安全API的入口点必须:
- 首先,将函数调用重定向到检查特权级别的安全固件代码。

6. 安全状态转换与特权级别变化(续)

由于Armv8 - M架构的定义方式,当安全软件库中的安全API被非安全异常处理程序调用时,将以特权访问级别执行。若需要将安全API的访问权限限制为非特权级别,安全API的入口点必须:
- 首先,将函数调用重定向到检查特权级别的安全固件代码。
- 然后,根据检查结果决定是否允许访问。

下面通过一个mermaid流程图来展示安全状态转换与特权级别变化的逻辑:

graph TD;
    A[函数调用/返回] --> B{处理器模式};
    B -- 线程模式 --> C{是否跨安全状态};
    C -- 是 --> D{特权级别变化};
    C -- 否 --> E[无特权级别变化];
    B -- 处理模式 --> F[保持特权级别];
    D -- 从非安全到安全 --> G[特权级别变化可能];
    D -- 从安全到非安全 --> H[特权级别变化可能];

这种机制确保了在不同的安全状态和处理器模式下,特权级别能够合理地变化,从而保障系统的安全性和稳定性。

总结

Armv8 - M TrustZone的安全机制为系统的安全运行提供了强大的支持。通过SAU寄存器的配置和管理,可以灵活地进行内存分区,实现安全和非安全区域的划分。非安全软件调用安全API和安全代码调用非安全函数的机制,在保障安全的前提下,实现了不同安全级别的软件之间的交互。BXNS和BLXNS指令以及相关的状态转换和特权级别变化规则,进一步增强了系统的安全性和稳定性。

以下是对整个安全机制关键要点的总结表格:
| 要点 | 描述 |
| ---- | ---- |
| SAU寄存器 | 包含多个可编程寄存器,用于内存分区和安全属性设置。 |
| 非安全软件调用安全API | 需满足SG指令和NSC区域条件,防止非法访问。 |
| 安全代码调用非安全函数 | 使用BLXNS指令,通过FNC_RETURN隐藏安全地址。 |
| BXNS和BLXNS指令 | 用于安全状态切换,仅安全软件可用。 |
| 安全状态转换与特权级别变化 | 根据处理器模式和安全状态决定特权级别。 |

在实际应用中,开发人员需要深入理解这些机制,合理配置寄存器和使用相关指令,以确保系统的安全性和可靠性。同时,要注意遵循安全编程的最佳实践,避免因疏忽导致安全漏洞。例如,在设置SAU寄存器时,要确保未使用区域的使能位被正确清除;在调用安全API和非安全函数时,要严格遵循相关的条件和规则。通过这些措施,可以充分发挥Armv8 - M TrustZone安全机制的优势,构建更加安全的系统。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值