]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: support control flow guard on windows/amd64
authorqmuntal <quimmuntal@gmail.com>
Sun, 2 Oct 2022 11:24:34 +0000 (13:24 +0200)
committerMichael Pratt <mpratt@google.com>
Thu, 3 Nov 2022 17:41:30 +0000 (17:41 +0000)
The stack pointer must lie within system stack limits
when Control Flow Guard (CFG) is enabled on Windows.

This CL updates runtime.sigtramp to honor this restriction by
porting some code from the windows/arm64 version, which
already supports CFG.

Fixes #53560

Change-Id: I7f88f9ae788b2bac38aac898b2567f1bea62f8f3
Reviewed-on: https://go-review.googlesource.com/c/go/+/437559
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Michael Pratt <mpratt@google.com>
Run-TryBot: Michael Pratt <mpratt@google.com>

src/runtime/sys_windows_amd64.s

index 1467b4d57bf01b9d7ef50c80f3dac851094a287e..4e00f64fae27048da58c6ba2b95a1c39fe05a038 100644 (file)
@@ -116,6 +116,7 @@ TEXT sigtramp<>(SB),NOSPLIT|NOFRAME,$0-0
        // Make stack space for the rest of the function.
        ADJSP   $48
 
+       MOVQ    CX, R13 // save exception address
        MOVQ    AX, R15 // save handler address
 
        // find g
@@ -153,8 +154,8 @@ TEXT sigtramp<>(SB),NOSPLIT|NOFRAME,$0-0
        MOVQ    DI, SP
 
 g0:
-       MOVQ    0(CX), BX // ExceptionRecord*
-       MOVQ    8(CX), CX // Context*
+       MOVQ    0(R13), BX // ExceptionRecord*
+       MOVQ    8(R13), CX // Context*
        MOVQ    BX, 0(SP)
        MOVQ    CX, 8(SP)
        MOVQ    DX, 16(SP)
@@ -162,6 +163,8 @@ g0:
        // AX is set to report result back to Windows
        MOVL    24(SP), AX
 
+       MOVQ    SP, DI // save g0 SP
+
        // switch back to original stack and g
        // no-op if we never left.
        MOVQ    40(SP), SP
@@ -169,12 +172,54 @@ g0:
        get_tls(BP)
        MOVQ    DX, g(BP)
 
+       // if return value is CONTINUE_SEARCH, do not set up control
+       // flow guard workaround.
+       CMPQ    AX, $0
+       JEQ     done
+
+       // Check if we need to set up the control flow guard workaround.
+       // On Windows, the stack pointer in the context must lie within
+       // system stack limits when we resume from exception.
+       // Store the resume SP and PC in alternate registers
+       // and return to sigresume on the g0 stack.
+       // sigresume makes no use of the stack at all,
+       // loading SP from R8 and jumping to R9.
+       // Note that smashing R8 and R9 is only safe because we know sigpanic
+       // will not actually return to the original frame, so the registers
+       // are effectively dead. But this does mean we can't use the
+       // same mechanism for async preemption.
+       MOVQ    8(R13), CX
+       MOVQ    $sigresume<>(SB), BX
+       CMPQ    BX, context_rip(CX)
+       JEQ     done                    // do not clobber saved SP/PC
+
+       // Save resume SP and PC into R8, R9.
+       MOVQ    context_rsp(CX), BX
+       MOVQ    BX, context_r8(CX)
+       MOVQ    context_rip(CX), BX
+       MOVQ    BX, context_r9(CX)
+
+       // Set up context record to return to sigresume on g0 stack
+       MOVD    DI, BX
+       MOVD    BX, context_rsp(CX)
+       MOVD    $sigresume<>(SB), BX
+       MOVD    BX, context_rip(CX)
+
 done:
        ADJSP   $-48
        POP_REGS_HOST_TO_ABI0()
 
        RET
 
+// Trampoline to resume execution from exception handler.
+// This is part of the control flow guard workaround.
+// It switches stacks and jumps to the continuation address.
+// R8 and R9 are set above at the end of sigtramp<>
+// in the context that starts executing at sigresume<>.
+TEXT sigresume<>(SB),NOSPLIT|NOFRAME,$0
+       MOVQ    R8, SP
+       JMP     R9
+
 TEXT runtime·exceptiontramp(SB),NOSPLIT|NOFRAME,$0
        MOVQ    $runtime·exceptionhandler(SB), AX
        JMP     sigtramp<>(SB)