1
0
mirror of https://github.com/golang/go synced 2024-09-29 16:34:31 -06:00

runtime: support control flow guard on windows/amd64

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>
This commit is contained in:
qmuntal 2022-10-02 13:24:34 +02:00 committed by Michael Pratt
parent 7abc8a2e33
commit 5c0d314adc

View 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)