这是四部分系列文章的第三部分,介绍了独特的产品 MPU‑Plus® 和使用 Cortex-M 内存保护单元 (MPU) 来提高微控制器单元 (MCU) 安全性的方法。第 2 部分介绍了分区、安全启动、MPU 控制和系统调用。 第 1 部分介绍了一些介绍性概念:MMU 与 MPU、对安全性、保护目标、MPU-Plus 快照、Cortex-v7M 和 v8M 以及 MPU 操作的日益增长的需求。
分区问题
定义分区只是安全过程中的一步。我们还必须关注黑客入侵分区后会做什么。在这方面,出现了四个主要问题领域:
堆使用。
函数调用 API。
中断。
任务创建和控制。
还有其他的,但这些现在就可以了。下面讨论解决方案。
堆
特别是对于面向对象的语言,在现代应用程序代码中使用堆是很流行的。随着嵌入式系统变得更加复杂并且预计会执行更多操作,尤其是在物联网系统中,这是一个不断增长的趋势。此外,一些中间件使用堆。
utasks 直接访问主堆显然是不可接受的。黑客可以很容易地通过耗尽或破坏整个系统来破坏整个系统。因此,必须在需要堆的 umode 分区和可能的 pmode 分区中使用专用堆。为了解决这个问题,最近升级了eheap™以支持多个堆。这些堆通常很小,但不一定如此。鉴于它倾向于支持小堆,这是一个很好的解决方案。有关更多信息,请参阅:
eheap 用户指南, Ralph Moore,Micro Digital, Inc.
图 6 说明了从主堆分配一个小的专用堆。来自 TaskA 的堆调用仅在该堆上运行,不能超出该堆。TaskA 只能访问受保护块或受保护消息的主堆,如虚线所示,不能超出受保护块。(受保护的块和消息将在后面讨论。)因此,主堆受到 TaskA 的保护,TaskA 可能是 utask 或 ptask。
专用堆的内存也可以是链接器分配的静态内存块。
函数调用 API
函数调用是软件部分之间的主要 API。这就产生了一个问题。例如,应用程序分区可能需要文件系统服务。因此,文件系统 API 函数必须可供它访问。文件系统中的子例程必须可供文件系统 API 函数访问,并且驱动程序函数必须可供子例程访问。此外,所有这些函数都必须可以访问文件缓冲区和全局变量。因此,整个蜡球——文件系统和驱动程序——最终位于应用程序分区的代码区域中,而文件缓冲区和全局变量最终位于应用程序分区的数据区域中。更糟糕的是,如果其他分区需要文件 I/O,那么这些区域将成为这些分区之间的公共区域。
如果黑客侵入其中一个分区,他就可以通过公共区域访问其他分区。虽然他不一定能控制那些分区,但他肯定可以把它们弄下来,甚至可能破坏整个系统。这个问题的解决方案是分区门户,这将在第 4 部分中讨论。
中断
中断会导致立即切换到 pmode,从而将 pmode 暴露给外部。回想一下,任何 pmode 功能都距离打开 Vault 仅一步之遥,这是一个严重的安全问题。在许多情况下,如图 7 所示,只需要在 ISR 或 ISR + LSR 中精心编写的几行代码。(LSR 提供延迟中断处理。)
不幸的是,有限数量的 MPU 插槽加剧了中断问题。最初,我们定义了一个sys_code区域来包含中断所需的 ISR 和其他系统代码,以及一个用于所需数据的sys_data区域。Vault、Security 和其他敏感分区被排除在这些区域之外。sys_code 和 sys_data 存在于每个任务 MPA 中。因此,当发生中断时,ISR 和 LSR 可以运行,但对其他 pcode 和 pdata 的访问权限有限。如果 MPU 有足够的插槽,这仍然是我们的首选方案。
sys_code 和 sys_data 区域是特权区域,因此不能由 utasks 使用。不幸的是,我们发现对于 8 插槽 MPU,我们不能为每个 utask 浪费两个插槽。因此,每当切换到 utask 时,标准 MPU-Plus 都会打开背景区域 (BR)。BR 在 umode 中不起作用,但是当中断发生时它允许 ISR 和 LSR 运行。不幸的是,在 pmode 中打开 BR 也允许访问所有内容 - 因此 Vault 是打开的!
在可行的情况下,建议 ISR 立即将最少的 sys_code 和 sys_data 区域加载到 MPU 中并关闭 BR。这至少会关闭保险库并使访问它变得更加困难。退出时,ISR 当然必须恢复被替换的区域。
对于 ptask,sys_code 和 sys_data 区域存在且可用。它们有些扩大以包括其他系统功能。因此,这两个区域不会造成问题,并且每当运行 ptask 时都会关闭 BR,以保护 Vault 等。
图 8 说明了采用的方法。注意 ptask 的 sys_code 和 sys_data 区域。utask 没有这些区域,因为 BR 已打开。因此,可以将 utask MPA 扩展两个插槽。这样就可以将 MPU 插槽 4 中的外围区域分别拆分为插槽 4 和 5 中的单独 USB 主机和 UART1 区域。这提供了更好的安全性,因为 USB 主机和 UART1 之间的内存中有几个外围设备,现在这些外围设备被 utask 排除在访问之外。插槽 6 也可用于动态区域(参见第 4 部分)。请注意,对于这两个任务,都有任务代码和任务数据区域以及公共代码和公共数据区域。后一个区域对于 ptask 和 utask 是不一样的——即使 ptask 最终变成了 utask。
当需要超过最小的中断处理时,图 9 在左侧说明了要做什么,右侧是不做什么。目标是将尽可能多的处理转移到可以更好地遏制黑客攻击的 utask 中。在这里,对于简单的中断,目标是 ISR 和 LSR 中的代码最少。此外,必须仔细编写此代码——它必须采用广泛的范围检查和其他旨在抵御黑客攻击的测试。如果还需要高性能,这是具有挑战性的。
尽管有上述注意事项,但可能需要在 pmode 中进行完全中断处理(即图 9 的右侧)。这肯定更快更简单,特别是如果有代码的关键部分并且正在调用系统服务。在这种情况下,最好在 ptask 中进行处理,而不是在 ISR 或 LSR 中进行处理,因为 ptask 提供了更多的保护,因为 BR 被禁用,因此它仅限于 MPU 区域。
更多中断问题
中断问题不会消失。另一组问题围绕着禁用和启用中断。在 umode 中,这两个操作是无操作的。所以,如果中断被禁用以保护 umode 代码中的关键部分,你猜怎么着?他们没有被禁用,你有一个隐藏的问题!在将遗留代码转换为 ucode 时,这可能会让人头疼,因为中断禁用通常用于保护代码的关键部分。也不能从 umode 禁用中断。如果可以的话,这将是黑客的战场。请注意,这在 pmode 中不是问题,因为所有特权指令都可以在 pmode 中访问。
解决这个问题的方法是允许 utasks 屏蔽和取消屏蔽特定的中断,使用 smx 函数 sb_IRQMask(irq_num) 和 sb_IRQUnmask(irq_num)。允许任务屏蔽和取消屏蔽的 IRQ 范围存储在其 TCB 中。因此,黑客可以造成的破坏仅限于任务使用的中断。对于遗留代码,有必要跟踪所有中断被禁用和启用的位置,用屏蔽和取消屏蔽替换它们,然后将允许的 IRQ 范围加载到任务 TCB 中。
为了帮助找到 umode 中中断禁用和启用的用途,如果在 umode 中调用,可以使用中断禁用和启用宏或函数的替代版本。这些有助于从宏和包装函数或预期在 pmode 中运行的代码中查找误用。
任务创建和控制
显然,如果黑客可以从他已经渗透的 umode 分区中创建、删除、启动和停止任务,他真的会造成麻烦。因此,在 umode 中不应允许任务功能。有人会认为所有任务的创建和控制都应该只在 pmode 中执行。
不幸的是,这不能很好地工作,尤其是在转换遗留代码时。要求在 pmode 初始化期间创建所有任务会导致意想不到的限制和复杂性。在许多情况下,需要根据需要创建任务,以便在事件发生时处理它们。例如,可以在插入 USB 设备时创建任务,并且可以在拔下 USB 设备时删除任务。作为另一个示例,一些 USB 控制器可以在主机和设备模式之间切换,因此需要禁用一个 USB 堆栈并启用另一个。为了节省资源,这很可能通过删除一组任务并创建另一组任务来实现。
这个问题的解决方案是任务族,如图 10 所示。通常,一个分区将有一个父任务或根任务,它在 pmode 中创建并在 pmode 中运行以执行某些分区初始化。后者可能包括创建或产生一些子任务。父任务然后将自己切换到 umode,它可以在其中启动其子 utask,并可能创建和启动其他任务。这为动态任务控制提供了必要的灵活性。图 8 说明了一个任务族。请注意,子任务可以创建其他子任务,从而成为这些子任务的父任务。
父任务可以在其子任务上创建、启动、停止、删除和执行其他功能。它不能对其父级或兄弟级执行这些任务功能,也不能对其子级执行这些任务功能。除此限制外,子级还继承其父级的 MPA 模板和所有其他父级限制。因此,孩子不能做任何父母不能做的事情。(否则,黑客可能会滋生怪物。)
任务本地存储 (TLS)
任务创建函数允许创建跟随任务堆栈的寄存器保存区域 (RSA) 的 TLS 区域:
TCB_PTR smx_TaskCreate(乐趣,pri,tlssz_ssz,fl_hn,名称)
tlssz_ssz 是一个拆分参数:高 16 位定义 TLS 大小 tlssz,低 16 位定义堆栈大小 ssz。两者都可以达到 64 KB。TLS 仅在 ssz 》 0 时可用——即任务堆栈必须是来自堆 hn 的永久堆栈。TLS 是一个额外受保护的任务数据块,不需要额外的 MPU 区域。它可以以与受保护数据块相同的方式使用(参见第 4 部分)。
TLS 指针存储在任务的 TCB 中。可以通过以下方式访问:
dp = (u8*)smx_TaskPeek(ut2a, SMX_PK_TLSP);
utasks 和 ptasks 都允许此操作。TLS 只能包含结构和数组(即缓冲区)。如果所有任务静态变量都定义为结构字段,任务缓冲区定义为数组,则 TLS 可以替换 task_data 区域,只要没有其他任务尝试访问任何变量(如果是,请将它们放入com_data 区域)。这释放了任务数据槽以用于另一个区域,以便创建更小、更安全的区域。图 8 是这种优势的主要示例。
审核编辑:郭婷
-
控制器
+关注
关注
112文章
16150浏览量
177217 -
寄存器
+关注
关注
31文章
5305浏览量
119904 -
usb
+关注
关注
60文章
7887浏览量
263824
发布评论请先 登录
相关推荐
评论