OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 3864|回复: 0

实现 MPU 安全~~~~~~~~~~~~~~~~~~

[复制链接]

42

主题

42

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
231
金钱
231
注册时间
2020-4-23
在线时间
22 小时
发表于 2021-7-14 17:08:15 | 显示全部楼层 |阅读模式
加密、身份验证和其他安全方法可以很好地保护通过 Internet 传输的数据和程序更新。也就是说,除非一端很容易被黑客入侵以窃取密钥并可能植入恶意软件以供将来激活。然后,在系统运营商不知情的情况下,机密信息每天都在被盗,可能的重大服务中断就在眼前。
自 2005 年推出 Cortex-M 架构以来,已经出货了大量基于 Cortex-M MCU 的产品。其中许多产品都连接到 Internet。目前正在使用 Cortex-M MCU 开发许多新产品,并且由于物联网的经济激励,其中更大比例的产品将连接到互联网。在绝大多数情况下,这些嵌入式设备几乎没有或根本没有防止黑客入侵的保护措施。
大多数 Cortex-M MCU,无论是在现场还是在开发中,都具有内存保护单元 (MPU)。然而,由于交付产品的时间紧迫以及使用 Cortex-M MPU 的困难,这些 MPU 要么使用不足,要么根本没有使用。由于 MPU 要求 MPU 区域的大小为 2 的幂并且它们在大小边界上对齐,因此明显的大量内存浪费是内存有限的系统采用的另一个障碍。
然而,对于这些 MCU,MPU 和 SVC 指令是实现可接受安全性的唯一手段。因此,我一年半前就着手确定 MPU 的问题是否可以克服,是否可以设计一种实用的方法来升级后期和后期开发项目,以及使用 MPU 的新项目安全。我发现这样做是可行的,并且 MPU-Plus 已被开发以简化此过程。
所有现有的嵌入式系统都使用 Cortex-v7M 架构。一年多前宣布的 Cortex-v8M 架构提供了更好的安全保护。不幸的是,处理器供应商采用它的速度很慢,几乎所有新的 MCU 仍然使用 Cortex-v7M 架构。因此,后者将伴随我们很长一段时间。因此,本文介绍了将现有系统移植到 Cortex-v7M MPU 的分步过程。
港口
我最近完成了使用 Cortex-M MPU 将大量中间件移植到非特权模式 (umode) 分区的工作。移植的代码包括:
  • 文件演示。
  • 文件系统。
  • USB 大容量存储类驱动程序。
  • USB 主机堆栈。
  • Synopsys 主机控制器驱动程序。

总而言之,这相当于大约 20,000 行代码——不是一个小端口。
我从这个端口学到的教训是:
  • 有用!
  • 它可以由不是代码作者的人完成。

我对上面的代码有些熟悉,但我不是它的作者。此外,它是几年前创建的,远非移植到 MPU 的理想选择。此端口的重要性在于它证明了提高使用 Cortex-M 处理器和 MPU 的项目后期和项目后系统的安全性的可行性。
关于后期项目系统:虽然做一些预先安全规划绝对是一个好主意,但安全确实为开发项目增加了另一个复杂度。实际上,此类项目很难按计划实现功能设计目标。增加安全性可能会导致设计工作浪费和错过时间表。我意识到这种异端思想值得被放逐到网络空间的黑暗角落,但它是务实的。我认为最好在制造提升期间增加安全性——即等到有值得保护的东西。
关于项目后系统,我相信有很多经理和工程师深切关注他们的系统在现场的脆弱性——特别是如果这些系统连接到黑客高速公路(又名互联网)。只要这些产品包含 Cortex-M MPU 并且它们的软件可以更新,这里也有希望。
安全事实
在讨论逐步移植过程以提高安全性之前,我们需要了解一些事实:
  • 没有安全措施是完美的。
  • 最终目标是比黑客的潜在收益更安全。
  • 安全改进是一个渐进的过程——可能需要很多次和很多年才能达到所需的水平。

提高安全性主要是通过将所有易受攻击和不受信任的代码放入 umode 并将密钥、安全软件(例如加密、身份验证、引导和更新代码)和关键任务代码放入特权模式 (pmode) 来实现的。MPU 防止 ucode 超出其分配的区域并限制如何访问这些区域(例如 XN = 从不执行)。被黑的 ucode 不能颠覆 pcode、窃取 pdata、从数据区域执行、溢出堆栈,也不能执行其他黑客技巧——它被装箱了。
分区
对代码进行分区是第一步。图 1 显示了我们可能称之为“第一次通过”的分区——即不是太雄心勃勃。在这种情况下,只有 5 个分区:以非特权模式 (umode) 运行的应用程序和中间件以及以特权模式 (pmode) 运行的初始化、系统服务和关键任务代码。每个分区包括一个或多个任务。

图 1:分区(Source Micro Digital)
初始化代码在正常任务操作开始之前运行。它通常在 MPU 关闭或打开并启用背景区域 (BR) 的情况下运行。因此,此代码可以访问任何内容并执行任何操作。这是可以的,因为它是安全启动的一部分,理论上不能被黑客入侵。安全启动超出了本文的范围。
系统服务包括异常处理程序、RTOS 和带有密钥的安全软件。关键任务软件通常是完成主要工作的少量软件。这些是值得信赖的软件。(当然,关键任务代码和密钥是我们试图保护的婴儿。)pmode 代码受到特权处理器状态支持的 MPU 区域和系统服务的软件中断 (SWI) API 的保护,不受 umode 代码的影响。用 SVC 指令实现。图 1 中的粗线表示 umode 和 pmode 之间的障碍。
如果已实现有效的硬件强制分离,则渗透任一 umode 分区的恶意软件无法访问 pmode 分区。
主控单元
const MPA mpa_tmplt_usbh ={ {RA("ucom_data") | V | 0, RW_DATA | N57 | RSIC(udsz) | EN}, {RA("ucom_code") | V | 1、UCODE | N7 | RSIC(ucsz) | EN}, {RA("usbh_data") | V | 2、RW_DATA | RSIC(usbdsz) | EN}, {RA("usbh_code") | V | 3、UCODE | N67 | RSIC(usbcsz) | EN}, {RA("syn_csr") | V | 4、RW_DATA | RSIC(synsz) | EN}, {RA("ur1_csr") | V | 5、RW_DATA | RSIC(ur1sz) | CN},};
这对应于图 2 所示的 umode MPU 结构。 pmode 有一个类似的模板。

创建区域

模板由区域组成。那么我们如何创建区域呢?一种方法是首先 在应用程序的 C 源代码模块中定义部分。例如,在每个包含特定区域代码的 C 模块中,代码[1] 的开头为:

#pragma default_function_attributes = @“.ucom_code”// 将所有ucom 函数放在这里。#pragma default_function_attributes =
“ucom_code”是段名称,用于标识包含 utask 之间公共代码的段。对于特定于 taskA 的代码,请使用节名称,例如“.taskA_code”。这 ”。” 选择节名之前是为了与标准编译器节名保持一致,例如 .text、.bss 等。任何数量的函数都可以包含在编译指示之间。此外,上述结构可以在其他模块中重复,所有功能将通过链接器合并到单个 .ucom_code 部分中。

数据使用:

#pragma default_variable_attributes = @“.ucom_data”// 将所有 ucom 数据放在这里。#pragma default_variable_attributes =
与代码一样,可以在编译指示之间包含任意数量的变量,并且可以在其他模块中重复上述结构以创建包含所有 ucom 变量的单个 .ucom_data 部分。当然,这也可以用于包含单个任务数据的部分,例如 .taskA_data。

在 ILINK 链接器命令文件 (.icf) 中,对于 .ucom_code 部分,请使用以下内容:

定义导出符号 ucsz = 0x8000;...定义块 ucom_code 大小 = 0x7000,对齐 = ucsz {ro section .ucom_code};...放入 ROM {block ucom_code, ...};
(0x8000 与 0x7000 将在下一节中解释。)如果需要,可以在 ucom_code 块中放置其他部分,如果需要,它们可以按固定顺序放置。在这个例子中,只有 .ucom_code 部分被放置在 ucom_code 块中。(请注意,节和块名称以“.”不同。)

在上面定义模板的 C 文件中:

#pragma section="ucom_code"extern u32 ucsz;
现在,可以在 MPA 模板定义中使用 ucom_code 和 ucsz,如上一节所示。因此,接头块变成 MPA 区域。这很方便,因为可以轻松控制它们的大小、对齐方式、顺序和其他特性。

链接器块

如前所述,链接器命令文件 (.icf) 中的块成为 MPA 模板中的区域,并最终成为 MPU 区域。使用链接器块可以避免分配错误的大小和/或对齐。如果块对于它包含的部分来说太小,链接器会抱怨。相反,链接器映射文件将显示链接器块是否太大。

为了给 .icf 中的链接器块分配大小和对齐方式,我们区分了三种大小:区域大小、标称大小和实际大小。例如,假设 ucom_code 的实际大小为 0x6B16。那么区域大小必须是下一个更大的 2 次方 = 0x8000 [2]。将区域大小除以 8 得到子区域大小 = 0x1000。现在找到 N 使得它是 0x8000 – N*0x1000 >= 0x6B16 的最大值。在这种情况下,N = 1,因此标称尺寸 = 0x7000。所以 ucsz = 0x8000 和标称块大小 = 0x7000。

最后一步是在MPA模板中ucom_code区域的rasr字段中放置N7(subregion 7 off),如上mpa_tmplt_usbh所示。如果我们忘记了这一点,usbh 任务将能够访问链接器在 ucom_code 区域之后的 0x1000 字节中放置的任何内容。另一方面,如果我们错误地放置了 N67(子区域 6 和 7 关闭),当代码尝试访问子区域 6 时,我们将得到内存管理错误 (MMF)。
MPU 有 8 个时隙,每个时隙可以包含一个区域。图 2 显示了 pmode 和 umode 的典型 MPU 结构。
单击以获取更大的图像

图 2:MPU 结构(来源 Micro Digital)
区域 7 是为任务堆栈区域保留的,由调度程序管理。该区域允许立即检测任务堆栈溢出并防止从堆栈执行代码。pmode 中的两个 sys 区域允许关闭 BR 以隔离 ptask。这对于从 ptasks 到 utasks 的逐步转换过程是必需的,如下所示。
其他区域从每个任务的内存保护阵列 (MPA) 加载,下面将讨论。task_code 和 task_data 区域特定于任务或其分区。pcom_code 和 pcom_data 区域在两个或多个任务或区域之间是公共的,而在 pmode 中,而 ucom_code 和 ucom_data 在两个或多个任务或区域之间是公共的,而在 umode 中。这在下面的分步过程讨论中得到了更全面的解释。
命令和状态寄存器 (CSR) 区域是 I/O 区域。umode 中的 syn_csr 和 ur1_csr(Synopsys USB 和 UART1)由于其 MPU 插槽不足,包含在 pmode 中的 apb0 csr 中。由于umode MPU 有更多的插槽,因此可以在umode 中提供更好的安全性。
海洋保护区
单击以获取更大的图像

图 3:每个任务的 MPA(来源 Micro Digital)
如图 3 所示,每个任务都有自己的内存保护阵列 (MPA)。MPA 与任务控制表中的 TCB 的顺序相同。当相关任务正在运行时,每个 MPA 都是 MPU 动态部分的副本。调度程序在调度任务时将 MPA 加载到 MPU 中。
此外,如图 3 所示,MPA 模板决定了 MPA 的内容。模板可以在 MPA 之间共享。对于同一分区中的任务,这往往是这种情况,尽管它们不需要具有相同的模板并且可能只共享几个区域。
每个 MPA 都是一个结构数组,由两个名为rbarrasr 的32 位字段组成。这些是每个 MPU 插槽中 MPU RBAR 和 RASR 寄存器的精确副本,除了在 r​​bar 中设置了有效位,而不是在 RBAR 中设置了有效位。下面是一个模板示例:



正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-5-24 01:37

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表