是否可以暂时抑制单个 ret 指令的英特尔 CET,或者以其他方式使用 retpolines?

2023-12-24

英特尔 CET(控制流执行技术)由两部分组成:SS(影子堆栈)和 IBT(间接分支跟踪)。如果您需要间接分支到您无法放置的某个地方endbr64由于某种原因,您可以抑制 IBT 一次jmp or call指令与notrack。有没有等效的方法来抑制单个SSret操作说明?

对于上下文,我正在考虑它将如何与 retpolines 交互,其中的关键控制流程或多或少类似于push real_target; call retpoline; pop junk; ret。如果没有办法压制SS的话ret,那么当启用 CET 时,retpolines 是否还有其他方法可以工作?如果没有,我们还有什么选择?我们是否需要为所有内容维护两套二进制包,一套用于需要 retpolines 的旧 CPU,一套用于支持 CET 的新 CPU?如果事实证明英特尔是错误的,而我们最终仍然需要在他们的新 CPU 上使用 retpolines,那又怎么样呢?我们是否必须放弃 CET 才能使用它们?


在玩了一下程序集之后,我发现你can将 retpolines 与 CET 一起使用,但不太理想。就是这样。作为参考,请考虑以下 C 代码:

extern void (*fp)(void);

int f(void) {
    fp();
    return 0;
}

编译它gcc -mindirect-branch=thunk -mfunction-return=thunk -O3 https://godbolt.org/z/Q88aS5产生这个:

f:
        subq    $8, %rsp
        movq    fp(%rip), %rax
        call    __x86_indirect_thunk_rax
        xorl    %eax, %eax
        addq    $8, %rsp
        jmp     __x86_return_thunk
__x86_return_thunk:
        call    .LIND1
.LIND0:
        pause
        lfence
        jmp     .LIND0
.LIND1:
        lea     8(%rsp), %rsp
        ret
__x86_indirect_thunk_rax:
        call    .LIND3
.LIND2:
        pause
        lfence
        jmp     .LIND2
.LIND3:
        mov     %rax, (%rsp)
        ret

事实证明,您只需将 thunk 修改为如下所示即可实现此目的:

__x86_return_thunk:
        call    .LIND1
.LIND0:
        pause
        lfence
        jmp     .LIND0
.LIND1:
        push    %rdi
        movl    $1, %edi
        incsspq %rdi
        pop     %rdi
        lea     8(%rsp), %rsp
        ret

__x86_indirect_thunk_rax:
        call    .LIND3
.LIND2:
        pause
        lfence
        jmp     .LIND2
.LIND3:
        push    %rdi
        rdsspq  %rdi
        wrssq   %rax, (%rdi)
        pop     %rdi
        mov     %rax, (%rsp)
        ret

通过使用incsspq, rdsspq, and wrssq根据说明,您可以修改影子堆栈以匹配对真实堆栈的更改。我测试了那些修改后的重击英特尔SDE https://software.intel.com/content/www/us/en/develop/articles/intel-software-development-emulator.html,它们确实使控制流错误消失了。

这是个好消息。这是坏消息:

  1. Unlike endbr64,我在 thunk 中使用的 CET 指令在不支持 CET 的 CPU 上不是 NOP(它们会导致SIGILL)。这意味着您需要两组不同的 thunk,并且需要使用 CPU 调度来根据 CET 是否可用来选择正确的 thunk。
  2. 使用 retpolines 意味着您不再执行任何间接分支,因此虽然您仍然可以获得 SS 的好处,但您已经完全否定了 IBT。我想你可以通过以下方式解决这个问题__x86_indirect_thunk_rax检查是否存在endbr64指令,但这真的很不优雅,而且可能会很慢。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

是否可以暂时抑制单个 ret 指令的英特尔 CET,或者以其他方式使用 retpolines? 的相关文章

随机推荐