这是四部分系列文章的第二部分,介绍了独特的产品 MPU-Plus 和使用 Cortex-M 内存保护单元 (MPU) 来提高微控制器单元 (MCU) 安全性的方法。第 1部分介绍了一些介绍性概念:MMU 与 MPU、对安全性、保护目标、MPU-Plus 快照、Cortex-v7M 和 v8M 以及 MPU 操作的日益增长的需求。
图 1:分区
图 1 说明了我们为安全而努力实现的软件结构。在此图中,椭圆表示隔离的分区。粗线以上的分区以umode(非特权或用户模式)运行,粗线以下的分区以pmode(特权或保护模式)运行。粗线表示非特权操作和特权操作之间的界限。这种隔离由 Cortex-M 处理器架构强制执行。它是安全可靠的,除非我们做错了什么。
粗线上方是两个应用程序分区和一个中间件分区。当然,实际系统可能有更多的 umode 分区。这里的目标是实现一个 umode 分区与另一个分区的完全隔离。然后穿透一个分区不会使黑客能够穿透其他分区,因此可以控制违规行为。每个 umode 分区是一组一个或多个 utask。utask 构成了与其他分区中的任务隔离的基础,但不是与自己分区中的任务隔离的基础。umode 分区具有强隔离能力。因此,应尽可能将易受攻击的代码(如驱动程序、中间件和应用程序代码)放入 umode 分区。
粗线以下是安全启动、pcode、smx、SMX RTOS 内核和安全分区。这些由 pcode 组成。当然,实际系统可能有更多的 pmode 分区。目标是也将 pmode 分区彼此隔离。但是,这种隔离不如 umode 隔离那么强,后面会讨论。
安全启动
当系统启动或重新启动时,处理器以 pmode 启动,并且位于 Secure Boot 分区中。
图 2:安全启动
如图 2 所示,安全启动软件进行基本的硬件和软件初始化,加载代码,如有必要,创建启动操作所需的任务,然后启动调度程序。在启动调度程序之前,没有任何任务正在运行。启动调度器后,系统以任务模式运行,第一个以最高优先级调度的任务正在运行。其他分区进行自己的初始化。出于结构和安全原因,最好将安全引导分区中的代码最小化。在图 2 中,安全引导加载程序以黄色显示。这些可以从许多来源获得,并且超出了本文的范围。绿色显示的代码是系统和应用程序代码。
smx
SMX RTOS由smx 内核和中间件组成。SMX 被拆分,因此 smx 内核在 pmode 下运行,而 SMX 中间件在 umode 下运行。MPU-Plus 与 SMX、eheap ™ 和某些其他产品捆绑在一起时,构成SecureSMX ™。
smx分区包含smx内核和SVC Handler、PendSV Handler等相关软件。它以 pmode 运行,以便将其与可能已损坏的 umode 分区强烈隔离。MPU-Plus 扩展了 smx 以添加安全功能。有关这些的更多信息,请参阅:
smx 用户指南, Ralph Moore,Micro Digital, Inc.
smx 参考手册, Ralph Moore, Micro Digital, Inc.
我们发现,除了添加 MPU-Plus 之外,还需要对 smx 本身进行大量修改,尽管 smx 已作为嵌入式内核使用了 30 年!中间件产品也需要进行重大修改。安全似乎正在给嵌入式系统软件带来范式转变。
安全
最后是安全分区和保险库。Vault 是我们存储珠宝(加密密钥、密码、验证码、证书等)和现金(私人数据)的地方。如果 pmode 被破坏,避难所就会弹开,王国就会消失。因此,保护 Vault 至关重要,只有包含加密、身份验证和其他安全任务的安全分区才能访问 Vault。
加密和身份验证软件已从 SMX 中间件产品中移出到安全分区中。因此,只有安全软件才能访问 Vault。
代码
pcode 分区包含中断服务例程 (ISR)、链接服务例程 (LSR) 和其他必须处于 pmode 的代码。这是系统、中间件和应用程序代码的混合体。在实际系统中,这可能会分为系统分区和应用程序分区。它可能包含一些 ptask 以及 ISR 和 LSR。同样, smx 错误
Manager、smx_EM() 和错误恢复代码不是任务。因此,此分区中的大部分代码都在当前任务的上下文中运行。
处理中断会带来特殊的安全问题,这将在第 3 部分中讨论。
任务
utasks 可以提供高级别的隔离。这主要是因为他们无法访问 MPU。MPU 加载了允许任务访问的区域,包括访问权限(例如只读、从不执行等),但任务无法更改它们。如果背景区域打开,它在 umode 中无效。然而,一切都不是桃子和奶油——还有堆问题和函数调用问题,这些将在后面讨论。
任务
与 utasks 相比,ptasks 提供的隔离性较弱。这是因为一旦 ptask 被破坏,恶意软件只需一个步骤即可关闭 MPU 或打开其背景区域 (BR)。然后 MPU 区域没有效果。MPU 在 pmode 中毫无防备,而在 umode 中则坚不可摧。
但是,ptasks 可以通过捕获许多黑客技术(例如堆栈或缓冲区溢出、尝试从堆栈或缓冲区执行等)并在黑客获得实际控制权之前触发 MMF 来帮助挫败攻击者。然后,MMF 处理程序可以删除渗透的任务并重新创建它,希望系统操作中只有一个小问题。它还可以报告事件,这有助于发现和减少代码漏洞。
ptasks 对于捕获编程错误也很有用,并且可以成为通向 utasks 的有用步骤。
基本操作
MPU 控制
内存保护阵列 (MPA) 是一组要在任务切换上加载到 MPU 中的区域;每个任务都有一个 MPA。任务的索引用于在内存保护表中查找其 MPA,mpt[indexsmx_TaskCreate() 将当前(父)任务的 MPA 复制到正在创建的任务。如果 ct 是 ptask,它可以通过以下方式更改任务的 MPA:
smx_TaskSet(任务,SMX_ST_MPA,tp);
其中 tp 指向任务的 MPA 模板。
前述如图3所示。在该图中,MPA0、1和2共享模板mpa_tmplta。因此,三个对应的任务共享相同的区域。因此,它们很可能在同一个分区中。请注意,MPA3 使用模板 mpa_tmpltb。因此,相应的任务很可能在一个单独的区域中。第五个任务尚未创建,其 MPA 也未加载。
图 3:模板、MPA 和 TCB
MPA 中的插槽与 MPU 中的动态插槽一样多。大多数插槽都充满了链接器命令文件中定义的静态区域(一个乏味的过程)。但是,某些插槽具有指向在运行时动态创建的区域数组的指针。这些将在第 4 部分中详细讨论。具有最高优先级的顶部 MPU 正在使用的插槽是为任务堆栈区域保留的。任务栈是在创建任务时从主堆动态创建的,或者在调度任务时从栈池中获取。在任务运行时,对 MPU 的任何更新也会对其 MPA 进行,因此在任务切换期间无需保存 MPU 内容。
创建静态区域是一个费力的过程。例如,对于代码区域,有必要识别特定分区或特定任务所需的所有功能,包括子例程。Pragma 被插入到代码中,以将所有这些放入一个唯一的代码部分,例如:
#pragma default_function_attributes = @“.ut1a_text”
无效 tm05_ut1a(无效)
{
smx_SemSignal(sbr1);
}
#pragma default_function_attributes =
然后在链接器命令文件中定义一个块来保存此部分和相关部分,例如:
定义块 ut1a_code,大小 = 1024,对齐 = 1024 {ro section .ut1a_text,ro section .ut1a_rodata};
区域在链接器命令文件中定义,并在其中放置块,例如:
定义区域 ROM = mem:[从 0x00200000 到 0x002FFFFF];
放入 ROM {block t2a_code, ro section .tmplt, block ut1a_code, block ut2a_code, block ut2b_code};
回到代码中,定义了 MPA 中的一个槽:
#pragma section = “ut1a_code”
MPA mpa_tmplt_ut1a =
{
。..
RGN(3 | RA(“ut1a_code”) | V, 代码 | RSI(“ut1a_code”) | EN, “ut1a_code”),
。..
};
所有这些都是针对一个模板中的一个 MPU 区域完成的——显然是一个费力的过程。上面显示的模板宏(例如 RGN())可以减少工作并有助于减少错误。因为有些语句在代码中,有些在链接器命令文件中,所以该过程容易出错。不仅如此,很容易为代码区域遗漏一个晦涩的子程序或为数据区域遗漏变量,从而在调试期间导致烦人的 MMF(在调试的早期阶段关闭 MMF 的一个很好的理由)。
系统调用
ptasks 可以直接调用所有的 smx 和 system 函数,但是 utasks 不能直接调用它们,因为它们必须在 pmode 中执行。而是使用 SVC N 指令。对于 umode 代码,将包含 smx 和系统原型函数的 xapi.h 头文件替换为 xapiu.h 头文件。后者将 smx_ 调用映射到 smxu_ 调用,这些调用是调用 SVC N 的 shell 函数,其中 N 是系统调用 ID。但是,限制通话,对于 umode 是禁止的,会产生 Privilege Violation 错误。受限调用只能通过 pcode 进行。例如,utasks 不需要 smx_HeapInit(),如果从恶意软件调用,可能会导致系统损坏,因此没有 smxu_HeapInit()。定义了一组合理的受限调用。然而,该集合可以根据需要针对特定应用进行扩展或收缩。
图 4:系统调用
图 4 说明了 utasks 和 ptasks 的系统调用机制。SVC Handler 使用 N 作为索引,通过 SSR 跳转表到 smx 系统服务例程(SSR)。SSR 在 pmode 中执行,然后将结果返回给 SVC Handler。SVC 处理程序将此结果返回给 smxu shell 函数,后者将其返回给 utask。所有这些细节对调用者都是隐藏的,看起来就像是进行了正常的函数调用。umode 中不允许的系统调用会导致分支到特权冲突错误管理器 (PVEM),而后者又会调用 smx 错误管理器 (EM)。
请注意,来自 ptask 的 smx 调用直接转到 SSR,并且没有不允许的服务调用。
本系列的下一部分将讨论分区问题,包括堆使用、函数调用 API、中断、父子任务和任务本地存储。
审核编辑:郭婷
全部0条评论
快来发表一下你的评论吧 !