x86_64 上的影子堆栈实现
Shadow stack implementation on x86_64
在Control Flow Integrity中,受保护的影子堆栈是通过LDT 使用x86 段实现的。但在 x86_64 中禁用了分段。是否有任何其他机制可用于在 x86_64 上实现受保护的堆栈?
编辑
找到了最近的 paper,其中描述了几个备选方案。
我认为32位CFI的想法是在DS/ES/SS上设置一个限制,并将影子堆栈放在之外,所以它只能被破坏通过带有 gs:
段覆盖前缀的指令。
这只适用于 x86-64 上的兼容模式(32 位 user-space),因为 CS/DS/ES/SS 有固定的 base=0 并且当 CPU 是时没有限制在长模式中。
FS 和 GS 即使在长模式下也可以有一个 non-zero 基础,但即使您可以对这些段设置限制,这也与您需要的相反。 (这将保护常规内存免受带有 gs
前缀的指令的影响,而不是相反。)有趣的事实: 大多数 CPU 不支持对这些段的限制无论如何都是长模式。
对于 Linux x32 ABI(长模式下的 32 位指针),您可以将影子堆栈放在虚拟地址的低 4GiB 之外 space .普通 compiler-generated 代码总是注意将指针截断为 32 位。当前默认的 code-gen 策略 (-maddress-mode=short
) 是在每条带有内存操作数的指令上使用 address-size 前缀,但 rsp
除外,它假定始终为 zero-extended ].
这会导致 a lot of wasted address-size prefixes,但这意味着当前 gcc 为 x32 编译的代码肯定会截断指向 32 位的指针,即使有 UB,这使得 compiler-generated 代码不可能load/store 地址 space.
的低 4GiB 之外
我认为长模式没有任何通用的方法来使虚拟地址区域 space 只能通过某种特殊指令(前缀或其他指令)访问。因此,如果您要防御使用 64 位 operand-size 的普通代码,则没有任何选项可以用基线 x86-64 替换段技巧。您必须映射/取消映射影子堆栈,这会非常慢。
如今还有其他几种技术可用于执行/检查控制流。 Intel's CET (Control-flow Enforcement Technology) gives hardware support for various stuff, including a shadow stack. Grsecurity published a review / critique of it。他们的结论以“总之,英特尔的CET主要是微软的弱CFI实现加影子栈的硬件实现。” IDK 如果这篇评论是准确的。 Grsecurity 确实生产了一种竞争产品(他们承认这一点),因此可能存在一些偏见。我确信 CET 总比没有好。
另请参阅 https://github.com/huku-/research/wiki/Intel-CPU-security-features 以获取 x86(或可能特别是 Intel)的列表 CPU 有助于一般安全性的功能(如 MPX 边界检查),而不仅仅是 control-flow。
在Control Flow Integrity中,受保护的影子堆栈是通过LDT 使用x86 段实现的。但在 x86_64 中禁用了分段。是否有任何其他机制可用于在 x86_64 上实现受保护的堆栈?
编辑
找到了最近的 paper,其中描述了几个备选方案。
我认为32位CFI的想法是在DS/ES/SS上设置一个限制,并将影子堆栈放在之外,所以它只能被破坏通过带有 gs:
段覆盖前缀的指令。
这只适用于 x86-64 上的兼容模式(32 位 user-space),因为 CS/DS/ES/SS 有固定的 base=0 并且当 CPU 是时没有限制在长模式中。
FS 和 GS 即使在长模式下也可以有一个 non-zero 基础,但即使您可以对这些段设置限制,这也与您需要的相反。 (这将保护常规内存免受带有 gs
前缀的指令的影响,而不是相反。)有趣的事实:
对于 Linux x32 ABI(长模式下的 32 位指针),您可以将影子堆栈放在虚拟地址的低 4GiB 之外 space .普通 compiler-generated 代码总是注意将指针截断为 32 位。当前默认的 code-gen 策略 (-maddress-mode=short
) 是在每条带有内存操作数的指令上使用 address-size 前缀,但 rsp
除外,它假定始终为 zero-extended ].
这会导致 a lot of wasted address-size prefixes,但这意味着当前 gcc 为 x32 编译的代码肯定会截断指向 32 位的指针,即使有 UB,这使得 compiler-generated 代码不可能load/store 地址 space.
的低 4GiB 之外我认为长模式没有任何通用的方法来使虚拟地址区域 space 只能通过某种特殊指令(前缀或其他指令)访问。因此,如果您要防御使用 64 位 operand-size 的普通代码,则没有任何选项可以用基线 x86-64 替换段技巧。您必须映射/取消映射影子堆栈,这会非常慢。
如今还有其他几种技术可用于执行/检查控制流。 Intel's CET (Control-flow Enforcement Technology) gives hardware support for various stuff, including a shadow stack. Grsecurity published a review / critique of it。他们的结论以“总之,英特尔的CET主要是微软的弱CFI实现加影子栈的硬件实现。” IDK 如果这篇评论是准确的。 Grsecurity 确实生产了一种竞争产品(他们承认这一点),因此可能存在一些偏见。我确信 CET 总比没有好。
另请参阅 https://github.com/huku-/research/wiki/Intel-CPU-security-features 以获取 x86(或可能特别是 Intel)的列表 CPU 有助于一般安全性的功能(如 MPX 边界检查),而不仅仅是 control-flow。