CODOMs

CODOMs——论文总结

摘要

一.介绍

复杂的软件系统包含大量相互不信任或不可靠的软件组件,它们可以跨越多种粒度和目的:单个函数、编译单元、代码库、应用程序插件或设备驱动程序。

如果不能正确的隔离这些组件,会产生严重影响,不管是恶意还是疏忽的,比如权限升级、信息泄漏、拒绝服务以及缓冲区溢出导致的数据损坏。因此,系统安全性和弹性要求单独的软件组件被隔离在单独的域中

现有的体系结构缺乏对软件组件级别的隔离。目前只支持一些粗粒度的保护机制,在单独的地址空间中隔离用户进程,在特权处理器模式下运行OS内核。这样的机制带来不可忽略的运行时开销,并且只能由操作系统管理,这使得他们不适合在共享单一地址空间的软件组件之间提供细粒度的隔离

由于软件组件由代码和数据组成,组件的数据只能由他的代码访问,因此,只有当指令指针来自组件的代码时,组件指令才能访问组件的数据。

codom设计是由以下准则驱动的:
(1)软件由多个组件组成,包括可信的和不可信的,他们共享相同的地址空间。
(2)组件通过交互来执行动作。系统必须:a.支持低开销的跨域同步调用/返回。
b.提供受保护的域入口点
c.防止呼叫者和被呼叫者相互干扰
(3) 为了避免缓冲区拷贝,必须允许交互域安全地引用彼此的内部内存,这要求域能够有效的授予和撤销访问其内存区域的权限,并且能够验证所给指针的有效性。(这一部分并不是很理解)

codoms通过将每个页面与一个标记关联起来进行操作,并且多个(不一定是连续的)页面可以共享相同的标记。
代码页还与它们可以访问(以及如何访问)的标记列表以及执行特权指令的能力相关联。因此,域是以代码为中心的,指令指针本身决定它可以访问哪些页面和特权资源。此外,控制可以使用简单的调用/返回指令在可以忽略不计的运行时开销下在域之间进行切换。(代码页是什么记列表是什么权指令的能力

为了方便快速的跨域调用,codom允许使用应用程序控制的功能寄存器跨域就地共享数据。
这有助于安全共享任意区域(基指针和大小),此外,codom提供了对能力篡改的保护,并且可以比以前提出的系统更有效地执行选择性的、用户级的能力撤销。(啥叫能力篡改

我们使用一个周期精确的x86模拟器评估了codom,结果显示切换域会导致极低的开销。在更大的范围内,我们展示了codom能够将Linux内核中的每个模块隔离到自己的领域中,而运行时成本可以忽略不计。

二.CODOMS概念

codoms体系结构的目标是提供灵活的硬件机制来定义域,并支持跨域的低延迟控制和数据传输。

2.1 以代码为中心的软件组件隔离
以代码为中心的隔离包含了将软件组件作为一个单元的思想,软件组件用来识别代码、数据(动态和静态)以及用于跨组件交互的预定义接口。

域被定义为代码和数据页的任意集合,只有域的代码被允许自由访问其代码和数据。

这样使得指令指针可以作为访问域的功能,域实际上可以包含多个组件。

以代码为中心的隔离还强制域交互,如果允许一个域调用另一个域,他可以简单的调用被调用域中预定义的入口点来转移控制

4.1 硬件元素和保护原语

4.1.1 页表的功能(PTCaps)

页表功能(PTCaps)是作为页表扩展实现的,包括一个标记(64位)和标记存在(T),特权能力P和能力存储(S)位。后者存储在页表条目的未使用的位中,标记存储在与其扩展的页目录物理相邻的页中。T位允许为整个页表子树设置标签,最大限度地减少页表的空间和管理开销。P位指示在代码页中是否允许特权操作,以确保常规代码不能执行它们。S位标识可用于存储功能的页面。

4.1.2 访问保护水平

访问保护水平指定了四个有序的值:None,Use,Read和Write,Use是基于目标页面重载的:

  • capability storage pages:允许 加载/存储 能力 从/到 内存,不允许定期加载/存储。
  • 代码页:启用域入口点,允许调用到与系统可配置值对齐的地址。如果通过大小为0的功能访问,则表示一个未对齐的地址,并允许跨域使用任意返回地址和函数指针。

4.1.3 能力寄存器(CapRegs)

能力寄存器存储每个核有效的能力,存储在内存中的能力占用256位(32b),包括一个基地址和大小,一个两位的访问保护级别,一个撤销计数器地址,一个撤销计数器值和一个标志。
CapRegs的管理方式如下:

Create初始化一个能力寄存器,应用程序必须提供除标签之外的所有字段。标签由硬件设置(基于PC)以防止伪造,并且标签的APL缓存到CapReg,如果没有提供撤销计数器,则该功能是同步的。

Modify只能削弱访问保护级别,缩小访问能力的地址范围

Spill只允许在32b对齐的地址上,并且目标页面被标记为能力存储,可以(至少)用Use级别访问。同步功能只能被溢出到DCS,并且能力推入/弹出指令也被提供来与DCS交互。由于use级别确保代码不能直接读取或修改内存内容,这就确保了被动功能的完整性和不可伪造性

Probe使用CapReg检查对指针的解引用是否失败。

usage仅适用于有效功能,支持两种使用模型

隐式使用验证内存访问对有效能力的影响。这简化了对编译器的支持,并且可以透明地向现有的code添加功能。明确的使用是通过单独的说明来确定使用哪个CapReg。编译器可以使用它来最小化CapReg检查的数量,从而提高能源效率

4.1.4 域控制堆栈(DCS)

域控制堆栈(DCS)为溢出的权能提供内存,DCS是一种具有存储权能页的私有每线程内存结构,由于它是私有的,所以所有功能都可以被注入到它中,而不会破坏同步能力撤销。

DCS受到dcsb和dcsp寄存器的限制(图3),代码被隐式授予对该范围的Use访问权。非特权代码仅使用权能指令推/弹出间接地修改dcsp寄存器。

dcsb寄存器控制DCS框架。它只能由TCB修改,并且硬件确保pop操作不会跨DCS框架。§5.4进一步描述了DCS的操作。

4.1.5 异步功能撤销

异步功能撤销基于功能创建时设置的撤销字段,设置这些字段是一种特权操作,因为硬件使用它们来访问内存,撤销计数器的地址指向存储在内存中的撤销计数器。
只要某个功能的计数器值与存储在撤销计数器中的计数器值匹配,该功能就被认为是有效的。
当执行撤销指令时,codom首先验证该指令的标记是否与存储在功能上的标记相匹配。这确保了只有创建功能的域才能撤销它。codoms然后增加撤销计数器,通过将其保护级别设置为None,从而使所有使用相同计数器地址的功能失效。通过将不同的功能关联到不同的计数器,选择性撤销是可能的。
被动(存储在内存中)异步功能在从内存加载时,如果它们的计数器值与内存中的计数器值不匹配,则会惰性失效。

共享撤销计数器的有效的异步功能将立即失效。一种可能的实现是使用中央目录[27]来跟踪有效同步功能。在这种情况下,撤销核心向目录发出信 ,这反过来会使使用同一撤销计数器的所有功能失效
由于大多数功能是同步的(而不是异步的),所以这种操作很少发生

撤销计数器可以重复使用246-1次,直到它溢出(引发异常),并且系统中可以存在248个不同的计数器。当计数器在溢出后被重用时,系统必须确保使用溢出计数器并存储在当前地址空间的容量存储页中的所有容量都无效。然而,撤销计数器(246?1)的大小使得此类事件极为罕见。更重要的是,系统不必跟踪授予访问权限的数据功能

4.2 在硬件中实现访问保护列表

最近使用的标记的APLs缓存在每个CPU的APL缓存中(第0步)。这个缓存由操作系统管理,允许多路使用标签和apl的无限空间。

缓存将PTCaps tag映射到它的硬件版本HwTag和相应APL (HwAPL)的一部分。

HwAPLs包含与缓存标签相对应的2位保护级别(如果不存在,则使用None)。
在TLB miss时,codom将标签的APL条目缓存到TLB中(第1步)。

iTLB由APL缓存表项中的tag、HwTag和hwapl扩展,以及页表项中的特权能力位扩展。
dTLB扩展了HwTag和能力存储位。这个信息可以存储在一个单独的结构上,以优化能量和延迟,因为它只在一个TLB命中之后才需要。

当获取一条指令时,来自iTLB的相关信息被存储在currdom寄存器中(第2步),该寄存器对当前域的信息进行编码。由于许多指令序列驻留在同一个页面中,因此可以对其进行优化,以减少iTLB查找的次数和传递该信息所需的存储量。

每当currdom寄存器的内容被修改时,它之前的值就被复制到prevdom寄存器,提供之前执行域的标识。(第6步)
当一个能力被创建时,currdom寄存器的标签和HwAPL被复制到CapReg中(第3步)。处于有效能力中的HwAPL永远不会存储到内存中,而是在APL缓存被激活时进行恢复(从内存加载,第5步)。
当修改APL缓存表项时,需要重新加载该CPU的TLB表项和CapRegs中的HwTag和HwAPL,不需要类似TLB击落的操作,因为每个CPU有一个独立的APL缓存,它的信息不会泄露到被动功能中。
图4描述了codom访问检查(图3 第4步)。dTLB中的HwTag用于索引currdom寄存器的HwAPL,并检索目标地址的保护级别。相反,currdom寄存器中的HwTag用于检查控制流指令。
例如,一个32个条目的APL缓存需要一个5位的HwTag和一个64位的HwAPL(32个2位条目)。这同样适用于功能,除了削弱的功能是通过使用更严格的功能和HwAPL访问保护级别来实现的。保护检查与实际的缓存访问并行执行,以隐藏它们的延迟。

以代码为中心的方法支持粗粒度隔离,只需对代码进行最少或不进行更改。例如,图5显示了一个与内核隔离的用户,以及相互隔离的 络和磁盘子系统。

codom包含了特权级别的实现:(1)只允许用户use access访问Tramp,一个系统调用蹦床,然后跳转到内核(类似于Linux中的vdso,或kipin L4 [16]);(2)在内核代码页上设置特权能力位;(3)给予所有内核级域对用户的完全访问权(一个简单的return可以在用户处恢复执行)。

与特权级别不同,codom还可以编码不完全有序的层次域关系。例如,本例中的 络子系统和磁盘子系统可以相互隔离。因为它们是作为Linux内核模块动态加载的,所以PLT可以用来控制它们对内核的访问,前提是它在向它们传递数据时使用功能。
考虑到codom的灵活性,有一种向后兼容的替代方案可以确保子系统的隔离性:让子系统完全访问内核,但不能在它们之间访问。

同样的技术也可以应用于用户级。例如,应用程序只能被授予对加密组件的使用访问权,而加密组件又具有对应用程序的完全访问权。这允许在不向应用程序公开加密密钥的情况下使用加密。

5.4 例子:细粒度的隔离

CODOMs

在更细粒度的场景中,关系不是分层的,需要进一步的操作:(1)双方都必须使用功能来传递对数据的引用,指针应该针对它们进行验证;(2)由于相同的堆栈跨域使用,能力被用来授予访问部分;(3)调用者或被调用者中的一些体系结构状态可能需要对另一方隐藏;(4)调用者和被调用者可能需要使用不同的DCS框架。由于策略是软件提供的(而不是硬连接的),其他组织也可能。此外,它们的需求依赖于域信任关系。

我们开发了一个概念验证编译器和链接器支持,利用现有的abi来处理这些情况。开发人员可以标记函数和数据,将它们放在特定的域中。该信息与域信任关系一起嵌入到ELF二进制文件中。此外,接口编译器为域入口点列表生成调用者/被调用者存根。例程根据域之间的信任关系进行专门化(如果域完全信任彼此,则可以达到空存根的极限)。即使它可以由链接器生成,为简单起见,接口编译器也会生成PLT代码(“门”)。与其他系统一样,缺乏高级编译器支持迫使程序员显式地管理指针验证和堆栈参数之外的数据能力。

图6显示了使用上述工具的两个域的组织。堆栈被放置在一个单独的域上,并且只能通过同步功能(CapReg0)访问。这将确保其他线程在跨域调用后不能篡改返回地址。gate代码具有特权能力bit(管理dcsframe)和对所有域的写访问权。由于用户代码不能访问以前的DCS框架,因此可以安全地使用它们存储跨域信息。在完全隔离的场景中执行完整调用/返回所需的步骤(混合软件/硬件隔离的上限开销)是:

1)调用者:调用者存根首先将所有没有作为参数使用的寄存器放入堆栈并置零,向被调用者隐藏所有不必要的信息。同样的情况也适用于功能(推送到DCS)。然后存根将任何过程参数推入堆栈(如果有必要的话),并通过从CapReg0派生CapReg1来授予它们访问权限,并调整CapReg0以禁止访问之前的框架。最后,它调用PLT, PLT执行gate代码。

2)门(调用路径):gate代码将常规堆栈指针和dcsb寄存器保存到DCS中,并通过调整dcsb和dcsp寄存器创建一个新的DCS帧。然后,它通过将调用者的返回地址保存到DCS,用指向自己的返回路径地址的指针替换它,将自己注入到被调用者的返回路径中,并为被调用者创建返回到该地址的功能(图6顶部的CapReg2;注意字 零的使用,以避免对齐检查)。最后,gate跳到被调用存根中。注意,这个跳转已经存在于动态加载对象的PLT中。

3)被调用者:被调用存根通过将所有不是结果的寄存器和功能归零来向调用者隐藏其状态,然后返回到注入的门(多亏了CapReg2)。

4)门(返回路径):gate恢复它保存的状态,展开DCS帧,并跳转到调用者的返回地址。展开DCS框架可确保隐式撤销存储在其中的所有同步功能。

声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!

上一篇 2021年1月2日
下一篇 2021年1月2日

相关推荐