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

问题描述 投票:3回答:1

Intel CET(控制流执行技术)由两块组成。SS(影子堆栈)和IBT(间接分支跟踪)。如果你需要间接分支到某个地方,而你又不能把一个 endbr64 出于某种原因,你可以抑制单次的IBT。jmpcall 教学与 notrack. 是否有同等的方法来抑制单人的SS。ret 指令?

对于上下文,我在想这将如何与retpolines互动,其中的关键控制流多少有点像 push real_target; call retpoline; pop junk; ret. 如果没有办法压制SS的那一点 ret那么,当启用CET时,是否有其他方法让retpolines工作?如果没有,我们有什么选择?我们是否需要为所有东西维护两套二进制包,一套用于需要retpolines的旧CPU,一套用于支持CET的新CPU?如果英特尔的结论是错误的,而我们最终还是需要在他们的新CPU上使用retpolines呢?我们是否要放弃CET来使用它们?

assembly x86-64 intel spectre
1个回答
0
投票

在玩了一下汇编后,我发现你 可以 使用retpolines与CET,但不太理想。下面是如何做的。作为参考,考虑一下这段C代码。

extern void (*fp)(void);

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

编译它的时候 gcc -mindirect-branch=thunk -mfunction-return=thunk -O3 会产生这样的结果。

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

事实证明,只要把thunks修改成这样,就可以让它工作。

__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, rdsspqwrssq 指令,你可以修改影子堆栈来匹配你对真实堆栈的修改。我在测试这些修改后的thunks时,使用了 英特尔SDE他们确实让控制流的错误消失了。

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

  1. 不像... endbr64在不支持CET的CPU上,我在thunks中使用的CET指令不是NOPs(它们的结果是 SIGILL). 这意味着你需要两套不同的thunks,你需要使用CPU调度来根据CET是否可用来选择合适的thunks。
  2. 使用retpolines意味着你不再做任何间接分支,所以虽然你仍然会得到SS的好处,但你已经完全否定了IBT。我想您可以通过将 __x86_indirect_thunk_rax 验明正身 endbr64 指令,但那真的很不优雅,而且可能会很慢。
© www.soinside.com 2019 - 2024. All rights reserved.