IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> 实现完全 MCU 分区隔离:MPU 管理 -> 正文阅读

[嵌入式]实现完全 MCU 分区隔离:MPU 管理

这是关于为基于 MCU 的系统实现高安全性的系列文章中的第二篇。在这篇文章中涉及的安全基础,划分MCU软件,父/子任务,utasks和ptasks的优势。在本文中,我们将详细介绍 MPU 管理。如第一篇文章所述,这不是教程。为此,建议参考文章末尾的参考资料。

图 1 显示了任务控制块 (TCB)内存保护阵列 (MPA)MPA 模板之间的关系


图 1:模板、MPA 和 TCB 关系。(来源:作者)?

请注意,MPA 模板可能适用于单个 MPA 和任务,也可能在任务及其 MPA 之间共享。通常,在后一种情况下,任务将在同一分区中。还有一个不需要模板的默认 MPA。当没有为任务创建 MPA 时使用它。在接下来的部分中,我们将讨论如何定义模板。

定义区域

正如本系列的第一篇文章中所讨论的,定义分区的第一步是定义分区需要的代码、数据和 IO 区域以及某些标准区域,这些区域将在下面讨论。为此,第一步是定义部分

部分

为了定义部分,没有必要重新组织包含来自其他分区的代码或数据的模块。为此,可以使用编译指示,如下(注意:所有代码和说明均针对 IAR EWARM 工具套件)

#pragma default_function_attributes = @ ".t2a_text"
无效 ttCD18_t2a(无效)
{
…
}
#pragma default_function_attributes =

同样,对于数据:

#pragma default_variable_attributes = @ ".t2a_data"
u32 irq;
TCB_PTR 父级;
u32 tskctr;
#pragma default_variable_attributes =

分散在许多模块中的同一节 pragma 定义由链接器合并为一个节。如果模块在各处的编译指示变得过于混乱,那么可以将一个分区的代码和数据分组到相同的分区模块中。然后,可以使用命令行选项,而不是编译指示。例如,在一个分区模块的项目文件中的 Options?/?C/C++ Compiler?/?Extra Options 中,如下:

--section.bss=.t2a_bss
--section.data=.t2a_data
--section.text=.t2a_text
--section.rodata=.t2a_rodata
--section.noinit=.t2a_noinit

只需重命名编译器分配的节名称。(一定要覆盖Inherited settings。)如果一个分区的几个模块被分组到一个项目文件节点中,那么上面的内容只需要放在那个节点的选项中。或者,代替上述内容,将以下内容放入额外选项中:

-f $PROJ_DIR$\..\..\..\CFG\t2a.xcc

并将上述命令行放入一个新模块 t2a.xcc 中。?

链接器命令文件

节用于定义链接器命令文件中的区域块。例如,对于 v7M?(注意:v7M 是 ARMv7-M 架构的简写,v8M 是 ARMv8-M 架构的简写)

定义导出符号 t2acsz = 0x1000;
定义导出符号 t2adsz = 0x100;
…
定义块 t2a_code,大小 = t2acsz*6/8,对齐 = t2acsz {ro section.t2a_text, ro section.t2a_rodata};
定义块 t2a_data 大小 = t2adsz*5/8, 对齐 = t2adsz {rw section.t2a_bss, rw section.t2a_data};

t2a_codet2a_data是区域块,成为 MPU 区域。请注意,区域大小是 2 的幂。实际区域块大小是区域大小的 5/8、6/8、7/8 或 1 倍中最接近的较大值。这分别利用了最后3、2、1或 0个子区域的子区域禁用。请注意,区域块在区域大小上对齐。区域块分别放置在 ROM 和 SRAM 中,位于链接器命令文件的末尾。

对于 v8M,事情更简单、更高效:

定义导出符号 t2acsz = 0xB00;
定义导出符号 t2adsz = 0xA0;
…
定义块 t2a_code,大小 = t2acsz,对齐 = 32 {ro section.t2a_text, ro section.t2a_rodata};
定义块 t2a_data 大小 = t2adsz, 对齐 = 32 {rw section.t2a_bss, rw section.t2a_data};

在这种情况下,大小只需要是 32 (0x20) 的倍数,区域块只需要在 32 上对齐,如图所示。显然,v8M 的内存效率比 v7M 高得多。例如,t2a 代码对于 v7M 是 0x1000 * 6/8 = 0xC00 = 3072,对于 v8M 是 0xB00 = 2816。但是,有一些技术可以提高 v7M 内存效率。这些将在本系列的后续部分中介绍。

分区模板

一个分区模板由一个分区所需要的所有地区。对于 v7M,它在代码中定义,如下面的示例所示:

#pragma section = "sys_code"
#pragma section = "sys_data"
#pragma section = "t2a_code"
#pragma section = "t2a_data"
MPA mpa_tmplt_t2a =
{
?? RGN(0 | RA("sys_data")| V, DATARW | SRD("sys_data") | RSI("sys_data") | EN, "sys_data"),
?? RGN(1 | RA("sys_code")| V, CODE | SRD("sys_code") | RSI("sys_code") | EN, "sys_code"),?
?? RGN(2 | RA("t2a_data")| V, DATARW | SRD("t2a_data") | RSIC(t2adsz) | EN, "t2a_data"),
?? RGN(3 | RA("t2a_code")| V, CODE | SRD("t2a_code") | RSIC(t2acsz) | EN, "t2a_code"),
 ? RGN(4 | 0x40011000 | V, IOR | (0x9 << 1) | EN, "USART1"),
?? RGN(5 | V, 0, "spare"), /* 保留给动态区域 */
?? RGN(6 | V, 0, "spare"), /* 保留给动态区域 */
?? RGN(7 | V, 0, "stack"), /* 保留给任务栈 */
};

在上面,节名称,例如“t2a_code”是在链接器命令文件中定义和导出的。 ?RGN、RA、SRD、RSIRSIC是在 MPU 寄存器RBARRASR中生成字段的宏。第三个字段(例如“t2a_data”)允许为每个区域分配一个名称,以便在调试期间使用。它不会进入 MPU。

t2a 是一个 ptask。因此,标准区域sys_codesys_data是它通过直接函数调用获取系统服务所必需的。sys_code 包含 RTOS 和其他系统服务代码,sys_data 包含 RTOS 和其他系统服务所需的控制块(例如 TCB)和全局变量。接下来我们看到上面定义的 t2a_data 和 t2a_code。请注意,IO 区域 USART1 是使用常量定义的。区域 5 和 6 是可用作动态区域的备用区域。最后,区域 7 是为任务堆栈保留的。有两个备用区域是不寻常的。在实践中,分区通常需要超过 8 个区域。

v8M对应的分区模板为:

{
?? RGN(0, RA("sys_data") | DATARW, RLA("sys_data") | AI(0) | EN, "sys_data"),
?? RGN(1, RA("sys_code") | CODE, RLA("sys_code") | AI(0) | EN, "sys_code"),?
?? RGN(2, RA("t2a_data") | DATARW, RLA("t2a_data") | AI(0) | EN, "t2a_data"),
?? RGN(3, RA("t2a_code") | CODE, RLA("t2a_code") | AI(0) | EN, "t2a_code"),
?? RGN(4, 0x40011000 | IOR, 0x40011FFF | AI(1) | EN, "USART1"),
?? RGN(5, 0, 0, "spare"), /* 保留给动态区域 */
?? RGN(6, 0, 0, "spare"), /* 保留给动态区域 */
?? RGN(7, 0, 0, "stack"), /* 保留给任务栈 */
};

再次更简单,这次是由于更简单的 v8M MPU 寄存器结构。

如果将 t2a 转换为 utask ut2a,则对于 v7M:

MPA mpa_tmplt_ut2a =
{
?? RGN(0 | V, 0, "spare"), /* 保留给动态区域 */
?? RGN(1 | RA("svc_code") | V, CODE | SRD("ucom_code") | RSI("ucom_code") | EN, "ucom_code"),
?? RGN(2 | RA("ut2a_data") | V, DATARW | SRD("ut2a_data") | RSI("ut2a_data") | EN, "ut2a_data"),
?? RGN(3 | RA("ut2a_code") | V, CODE | SRD("ut2a_code") | RSI("ut2a_code") | EN, "ut2a_code"),
 ? RGN(4 | 0x40011000 | V, IOR | (0x9 << 1) | EN, "USART1"),
?? RGN(5 | V, 0, "spare"), /* 保留给动态区域 */
?? RGN(6 | V, 0, "spare"), /* 保留给动态区域 */
?? RGN(7 | V, 0, "stack"), /* 保留给任务栈 */
};

唯一的区别是 sys_data 和 sys_code 已被替换为备用插槽和svc_code。svc_code 是一个标准区域,它使 utask 能够通过 SVC 处理程序间接调用系统服务。备用插槽可用于动态区域。下面讨论动态区域。应该注意的是,由于 sys_data 和 sys_code 特权区域不存在,背景区域 (BR)必须打开才能为中断和异常提供服务。(BR 在 pmode 下生效,在 umode 下无效。)

MPU/MPA 关系

图 2 显示了 MPU 和 MPA 之间的关系。在系统初始化期间,静态插槽加载一次。这些可能包含特权区域,例如 sys_code 和 sys_data,以便允许 ISR 和异常处理程序在没有 BR 的情况下运行。由于需要更多活动插槽,因此 16 插槽 MPU 中很可能存在静态插槽,但 8 插槽 MPU 中则不然。


图 2:MPU/MPA 关系。(来源:作者)

?

当任务被分派时,活动槽被加载。每个 MPA 的活动区域的大小必须完全相同,在本例中为 6 个区域。请注意,插槽 7 中的 SR 区域是任务堆栈区域。这可以在分派任务时加载到 MPA 和 MPU 中,或者在创建 MPA 时加载到 MPA 中,然后在分派任务时加载到 MPU 中。最后,辅助插槽仅在 MPA 中,其数量因 MPA 而异。(MPA 是从主堆分配的,因此大小可能会有所不同。)

辅助插槽

辅助槽位用于有效增加MPU槽位数量。它们以两种方式使用:(1)用于受保护的消息(pmsgs),这将在以后关于分区门户的论文中讨论,以及用于插槽交换.?后者对 IO 区域特别有用。例如,USB 主机任务可能需要访问 USB OTG、DMA 和 USART 控制器。对于 STM32F746 处理器,它们分别位于:0x4004 0000 到 0x4007 FFFF、0x4002 6000 到 63FF 和 0x4001 1000 到 13FF。第一个需要从 256K 边界开始的 0x4 0000 = 256K 区域,第二个和第三个需要从 1K 边界开始的 0x400 = 1K 区域。这些区域可以加载到 3 个辅助 MPA 插槽中,并且在需要时,可以将一个区域交换到 MPA 和 MPU 中的活动 IO 插槽中。这在图 3 中针对两个辅助 IO 插槽进行了说明。


图 3:交换 IO 区域。(来源:作者)

?

如果只有一个活动 IO 插槽可用,如图所示,另一种方法是定义一个从 0x4000 0000 到 0x4007 FFFF 的区域——一个高达 0x8 000 = 512K 的区域!它将有 0x1 0000 大小的子区域,因此可以禁用第一个子区域(0x4000 0000 到 0x4000 FFFF)。因此,有效区域将覆盖从 0x4001 0000 到 0x4007 FFFF。这包括大约 20 个其他外设,例如以太网、GPIO、SPI、定时器和 ADC。USB 主机任务不应该访问其中的任何一个——这对于感染 USB 主机分区的黑客来说将是一个大白天!交换 IO 区域所需的少量时间非常值得增加分区隔离和安全性。

动态老虎机

模板还可以包含动态插槽。动态槽有一种方法来表明它不是静态槽,并且它有一个指向区域信息存储位置的指针。创建 MPA 时,该信息将加载到动态 MPA 插槽中。动态插槽的优点是可以即时创建所需大小的区域。例如,它们可以从堆中分配。这允许在运行时根据不同的安装或操作要求进行调整。需要注意的是,MPA 以及动态插槽只能在 pmode 中创建,因此只能由受信任的软件创建,这一点很重要。除了通过系统调用创建 pblocks 和 pmsgs 之外,侵入 umode 分区的黑客无法创建动态槽,这将在以后的论文中讨论。

堆栈区域

参考?1 提出了一个有趣的想法,即使用红色区域来防止堆栈溢出。这样做的优点是,它允许堆栈为它们的任务调整大小,并在可能包含其他公共变量的单个区域中彼此相邻。这可以在 v7M 系统中节省大量 RAM。红色区域是一个小区域(例如 32 字节)加载到任务开关的顶部 MPU 插槽中;它覆盖了任务堆栈的顶部。红色区域禁止所有访问,因此堆栈溢出(从红色区域下方)将导致 MMF。

虽然这可能有助于捕获一些堆栈使用错误,但对于安全性而言却毫无用处。由于某些黑客技巧,黑客可以通过在当前由任务运行的第一个恶意软件函数中定义一个大型本地数组来轻松跳过红色区域。您必须始终假设黑客对您自己的代码的了解与您一样多,甚至更多。因此他知道哪个堆栈适合哪个任务。因此,他将能够在他希望的任何堆栈中对他的第二个恶意软件函数进行错误返回。当该任务运行时,他将通过从其堆栈返回来获得对其的控制权。另外,红色区域使用了一个MPU插槽,所以它在堆栈区域上没有任何收益,堆栈区域也使用一个MPU插槽,就MPU使用而言。

一种理想的方法是在创建任务时从堆中分配一个堆栈。当然,这需要一个可以为 MPU 分配合适大小和对齐的块的堆。此外,对于 v7M,它必须设置子区域禁用以实现最佳的大于或等于拟合。另一种方法是使用静态堆栈或堆栈池,其中堆栈的大小和对齐已经正确。堆方法提供了更多的灵活性和效率,但都可以很好地确保安全性。在这两种情况下,堆栈区域都具有 RW 和 XN(eXecute Never)属性。XN 击败了许多黑客技巧。(越多越好!)。

作为使用堆栈区域的结果,堆栈溢出并尝试从堆栈执行会导致立即 MMF。黑客能做的最糟糕的事情就是破坏堆栈,并可能破坏其下方的任务本地存储 (TLS)。他不能损坏任何其他堆栈。为了获得最佳安全性,任务堆栈区域被放入顶部插槽。这是因为对于 v7M,当区域重叠时,较高编号槽的属性占优势。这可确保 XN 不会被覆盖。v8M 不允许区域重叠(稍后会详细介绍),因此这不是它的一个因素,但仍然使用顶部插槽以保持一致性。?

多任务分区模板

在许多情况下,一个分区只有一项任务。然而,正如本系列前一部分的父/子任务中所讨论的那样,除了主任务之外,可能还需要辅助任务。这允许将某些区域卸载到帮助程序或子任务,从而保持在 MPU 插槽限制内。为分区任务的 MPA 分配分区区域的方法如图 4 所示。


图 4:来自一个模板的多个 MPA。(来源:作者)

?

为简洁起见,该图假设一个 4 插槽 MPU。创建MPA1时,掩码M1选择活动区域A、B、C和D。创建MPA2时,掩码M2选择活动区域A、B、E和F以及辅助区域H和G。因此4槽MPU限制即使分区模板有 6 个活动插槽,也满足分区的要求。

结论

在前面我们已经研究了创建静态和动态区域的方法。此外,我们还介绍了创建分区模板并使用它们来初始化任务 MPA。我们还介绍了 MPU/MPA 关系以及静态、活动和辅助区域的定义。还研究了使用辅助区域来创建紧密的 IO 区域和任务堆栈区域的权衡。这是对 MPU 管理当前状态的非常完整的回顾。

在本系列的下一篇文章中,我们将研究为什么需要多个堆来实现高安全性。我们将研究在分区嵌入式系统中有用的堆特性,并研究从堆中分配对齐块区域块的方法。

相关实战:https://www.yunduoketang.com/article/zxjy122.html
https://www.yunduoketang.com/article/zxjy117.html
https://www.yunduoketang.com/article/zxjy118.html
https://www.yunduoketang.com/article/zxjy116.html
https://www.yunduoketang.com/article/rhkwk1.html

????????

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2021-07-17 12:06:30  更:2021-07-17 12:07:06 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 19:17:20-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码