当前位置: 首页 > 科技观察

OS-VirtualizationSecurityKA-ControlFlowLimitationofSystemHardening

时间:2023-03-13 11:42:45 科技观察

ControlFlowLimitation正交防线是为了规范操作系统的控制流。通过确保攻击者无法将控制权转移到他们选择的代码,即使我们不删除它们,我们也可以更难利用内存错误。最好的例子被称为控制流完整性(CFI),现在有许多编译器工具链(例如LLVM和Microsoft的VisualStudio),并于2017年以ControlFlowGuard的名称并入Windows内核-另请参阅软件安全CyBOK知识区。从概念上讲,CFI非常简单:我们确保代码中的控制流始终遵循静态控制流图。例如,一个函数的返回指令应该只允许返回到它的调用点,而使用C中的函数指针或C++中的虚函数的间接调用应该只能定位它应该能够定位的合法函数的入口点打电话。为了实现这种保护,我们可以标记间接控制传输指令(返回、间接调用和间接跳转)的所有合法目标,并将这些标记添加到特定于该指令的集合中。在运行时,我们检查指令即将到来的控制转移是否是集合中的目标。否则,CFI将发出警报和/或使程序崩溃。与ASLR一样,CFI也有多种风格,从粗粒度到细粒度,从上下文敏感到上下文不敏感。与ASLR一样,今天的大多数实现只采用最简单、最粗粒度的保护。粗粒度CFI意味着为了性能稍微放宽规则。例如,不是将函数的返回指令限制为仅针对可能调用该函数的合法调用点,而是可以针对任何调用点。虽然不如细粒度CFI安全,但它仍然极大地限制了攻击者的余地并且具有更快的运行时检查。现代机器上的硬件甚至支持(或将支持)某些形式的CFI。例如,英特尔控制流执行技术(CET)支持影子堆栈和间接分支跟踪,以帮助分别执行返回和转发控制传输的完整性(以非常粗粒度的方式)。ARM也不甘示弱,提供了指针认证来防止指针值被非法修改——主要是利用指针的高位存储指针认证码(PAC),其作用类似于对加密指针值的签名(除非你得到正确的PAC,否则您的指针无效)。遗憾的是,CFI只能帮助抵御通过破坏返回地址、函数指针和跳转目标等控制数据来改变控制流的攻击,而无法抵御非控制数据攻击。例如,它无法防止覆盖当前进程的特权级别并将其设置为“root”的内存损坏(例如,通过将有效用户ID设置为root用户的ID)。但是,如果对控制流的限制在实践中如此成功,您可能想知道是否可以对数据流进行类似的限制。事实上,它们确实如此,这被称为数据流完整性(DFI)。在DFI中,我们静态地确定每个加载指令(即从内存中读取的指令)存储指令可能合法地产生数据,并且我们标记这些指令并将这些标签放在一个组中。在运行时,对于内存中的每个字节,我们都会记住该位置的最后存储标签。当我们遇到加载指令时,我们会检查该地址的最后一个存储是否在合法存储集中,如果不在,我们会发出警报。与CFI不同,DFI在实践中并未被广泛采用,可能是因为其显着的性能开销。