Fix incorrect stack pointer usage in StgRun() on x86_64
authorBen Gamari <bgamari.foss@gmail.com>
Mon, 3 Aug 2015 06:42:00 +0000 (08:42 +0200)
committerBen Gamari <ben@smart-cactus.org>
Mon, 3 Aug 2015 06:42:15 +0000 (08:42 +0200)
The STG_RETURN code from StgCRun.c is incorrect for x86_64 variants
where the ABI doesn't impose a mandatory red zone for the stack, like on
Windows or Xen/HaLVM. The current implementation restores the stack
pointer first, which effectively marks the area with the saved registers
as reusable. Later, the CPU registers are restored from this "free"
area.

This ordering happens to work by accident on operating systems that
strictly adhere to the System V ABI, because any interrupt/signal
delivery is guaranteed to leave the first 128 bytes past the stack
pointer untouched (red zone). On other systems this might result in
corrupted CPU registers if an interruption happens just after restoring
the stack pointer.

The red zone is usually only used by small leaf functions to avoid
updates to the stack pointer and exploiting it doesn't give us any
advantage in this case.

Reviewers: austin, rwbarton

Reviewed By: rwbarton

Subscribers: thomie, simonmar

Differential Revision: https://phabricator.haskell.org/D1120

GHC Trac Issues: #10155

rts/StgCRun.c

index 2903911..6448509 100644 (file)
@@ -302,19 +302,18 @@ StgRunIsImplementedInAssembler(void)
          * restore callee-saves registers.  (Don't stomp on %%rax!)
          */
         "addq %0, %%rsp\n\t"
-        "movq %%rsp, %%rdx\n\t"
-        "addq %1, %%rsp\n\t"
-        "movq 0(%%rdx),%%rbx\n\t"       /* restore the registers saved above */
-        "movq 8(%%rdx),%%rbp\n\t"
-        "movq 16(%%rdx),%%r12\n\t"
-        "movq 24(%%rdx),%%r13\n\t"
-        "movq 32(%%rdx),%%r14\n\t"
-        "movq 40(%%rdx),%%r15\n\t"
+        "movq 0(%%rsp),%%rbx\n\t"       /* restore the registers saved above */
+        "movq 8(%%rsp),%%rbp\n\t"
+        "movq 16(%%rsp),%%r12\n\t"
+        "movq 24(%%rsp),%%r13\n\t"
+        "movq 32(%%rsp),%%r14\n\t"
+        "movq 40(%%rsp),%%r15\n\t"
 #if defined(mingw32_HOST_OS)
-        "movq 48(%%rdx),%%rdi\n\t"
-        "movq 56(%%rdx),%%rsi\n\t"
-        "movq 64(%%rdx),%%xmm6\n\t"
+        "movq 48(%%rsp),%%rdi\n\t"
+        "movq 56(%%rsp),%%rsi\n\t"
+        "movq 64(%%rsp),%%xmm6\n\t"
 #endif
+        "addq %1, %%rsp\n\t"
         "retq"
 
         :