Skip to content

Commit 5c0d314

Browse files
qmuntalprattmic
authored andcommitted
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>
1 parent 7abc8a2 commit 5c0d314

File tree

1 file changed

+47
-2
lines changed

1 file changed

+47
-2
lines changed

src/runtime/sys_windows_amd64.s

+47-2
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ TEXT sigtramp<>(SB),NOSPLIT|NOFRAME,$0-0
116116
// Make stack space for the rest of the function.
117117
ADJSP $48
118118

119+
MOVQ CX, R13 // save exception address
119120
MOVQ AX, R15 // save handler address
120121

121122
// find g
@@ -153,28 +154,72 @@ TEXT sigtramp<>(SB),NOSPLIT|NOFRAME,$0-0
153154
MOVQ DI, SP
154155

155156
g0:
156-
MOVQ 0(CX), BX // ExceptionRecord*
157-
MOVQ 8(CX), CX // Context*
157+
MOVQ 0(R13), BX // ExceptionRecord*
158+
MOVQ 8(R13), CX // Context*
158159
MOVQ BX, 0(SP)
159160
MOVQ CX, 8(SP)
160161
MOVQ DX, 16(SP)
161162
CALL R15 // call handler
162163
// AX is set to report result back to Windows
163164
MOVL 24(SP), AX
164165

166+
MOVQ SP, DI // save g0 SP
167+
165168
// switch back to original stack and g
166169
// no-op if we never left.
167170
MOVQ 40(SP), SP
168171
MOVQ 32(SP), DX
169172
get_tls(BP)
170173
MOVQ DX, g(BP)
171174

175+
// if return value is CONTINUE_SEARCH, do not set up control
176+
// flow guard workaround.
177+
CMPQ AX, $0
178+
JEQ done
179+
180+
// Check if we need to set up the control flow guard workaround.
181+
// On Windows, the stack pointer in the context must lie within
182+
// system stack limits when we resume from exception.
183+
// Store the resume SP and PC in alternate registers
184+
// and return to sigresume on the g0 stack.
185+
// sigresume makes no use of the stack at all,
186+
// loading SP from R8 and jumping to R9.
187+
// Note that smashing R8 and R9 is only safe because we know sigpanic
188+
// will not actually return to the original frame, so the registers
189+
// are effectively dead. But this does mean we can't use the
190+
// same mechanism for async preemption.
191+
MOVQ 8(R13), CX
192+
MOVQ $sigresume<>(SB), BX
193+
CMPQ BX, context_rip(CX)
194+
JEQ done // do not clobber saved SP/PC
195+
196+
// Save resume SP and PC into R8, R9.
197+
MOVQ context_rsp(CX), BX
198+
MOVQ BX, context_r8(CX)
199+
MOVQ context_rip(CX), BX
200+
MOVQ BX, context_r9(CX)
201+
202+
// Set up context record to return to sigresume on g0 stack
203+
MOVD DI, BX
204+
MOVD BX, context_rsp(CX)
205+
MOVD $sigresume<>(SB), BX
206+
MOVD BX, context_rip(CX)
207+
172208
done:
173209
ADJSP $-48
174210
POP_REGS_HOST_TO_ABI0()
175211

176212
RET
177213

214+
// Trampoline to resume execution from exception handler.
215+
// This is part of the control flow guard workaround.
216+
// It switches stacks and jumps to the continuation address.
217+
// R8 and R9 are set above at the end of sigtramp<>
218+
// in the context that starts executing at sigresume<>.
219+
TEXT sigresume<>(SB),NOSPLIT|NOFRAME,$0
220+
MOVQ R8, SP
221+
JMP R9
222+
178223
TEXT runtime·exceptiontramp(SB),NOSPLIT|NOFRAME,$0
179224
MOVQ $runtime·exceptionhandler(SB), AX
180225
JMP sigtramp<>(SB)

0 commit comments

Comments
 (0)