|
|
246e17 |
commit 5d844e1b72513cf59b5e7c14295644efdcc66e44
|
|
|
246e17 |
Author: H.J. Lu <hjl.tools@gmail.com>
|
|
|
246e17 |
Date: Fri Feb 14 14:45:34 2020 -0800
|
|
|
246e17 |
|
|
|
246e17 |
i386: Enable CET support in ucontext functions
|
|
|
246e17 |
|
|
|
246e17 |
1. getcontext and swapcontext are updated to save the caller's shadow
|
|
|
246e17 |
stack pointer and return address.
|
|
|
246e17 |
2. setcontext and swapcontext are updated to restore shadow stack and
|
|
|
246e17 |
jump to new context directly.
|
|
|
246e17 |
3. makecontext is updated to allocate a new shadow stack and set the
|
|
|
246e17 |
caller's return address to the helper code, L(exitcode).
|
|
|
246e17 |
4. Since we no longer save and restore EAX, ECX and EDX in getcontext,
|
|
|
246e17 |
setcontext and swapcontext, we can use them as scratch register slots
|
|
|
246e17 |
to enable CET in ucontext functions.
|
|
|
246e17 |
|
|
|
246e17 |
Since makecontext allocates a new shadow stack when making a new
|
|
|
246e17 |
context and kernel allocates a new shadow stack for clone/fork/vfork
|
|
|
246e17 |
syscalls, we track the current shadow stack base. In setcontext and
|
|
|
246e17 |
swapcontext, if the target shadow stack base is the same as the current
|
|
|
246e17 |
shadow stack base, we unwind the shadow stack. Otherwise it is a stack
|
|
|
246e17 |
switch and we look for a restore token.
|
|
|
246e17 |
|
|
|
246e17 |
We enable shadow stack at run-time only if program and all used shared
|
|
|
246e17 |
objects, including dlopened ones, are shadow stack enabled, which means
|
|
|
246e17 |
that they must be compiled with GCC 8 or above and glibc 2.28 or above.
|
|
|
246e17 |
We need to save and restore shadow stack only if shadow stack is enabled.
|
|
|
246e17 |
When caller of getcontext, setcontext, swapcontext and makecontext is
|
|
|
246e17 |
compiled with smaller ucontext_t, shadow stack won't be enabled at
|
|
|
246e17 |
run-time. We check if shadow stack is enabled before accessing the
|
|
|
246e17 |
extended field in ucontext_t.
|
|
|
246e17 |
|
|
|
246e17 |
Tested on i386 CET/non-CET machines.
|
|
|
246e17 |
|
|
|
246e17 |
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
|
|
|
246e17 |
---
|
|
|
246e17 |
|
|
|
246e17 |
diff --git a/sysdeps/unix/sysv/linux/i386/getcontext.S b/sysdeps/unix/sysv/linux/i386/getcontext.S
|
|
|
246e17 |
index 6637596..4ed9d03 100644
|
|
|
246e17 |
--- a/sysdeps/unix/sysv/linux/i386/getcontext.S
|
|
|
246e17 |
+++ b/sysdeps/unix/sysv/linux/i386/getcontext.S
|
|
|
246e17 |
@@ -18,6 +18,7 @@
|
|
|
246e17 |
<http://www.gnu.org/licenses/>. */
|
|
|
246e17 |
|
|
|
246e17 |
#include <sysdep.h>
|
|
|
246e17 |
+#include <asm/prctl.h>
|
|
|
246e17 |
|
|
|
246e17 |
#include "ucontext_i.h"
|
|
|
246e17 |
|
|
|
246e17 |
@@ -42,6 +43,61 @@ ENTRY(__getcontext)
|
|
|
246e17 |
movw %fs, %dx
|
|
|
246e17 |
movl %edx, oFS(%eax)
|
|
|
246e17 |
|
|
|
246e17 |
+#if SHSTK_ENABLED
|
|
|
246e17 |
+ /* Check if shadow stack is enabled. */
|
|
|
246e17 |
+ testl $X86_FEATURE_1_SHSTK, %gs:FEATURE_1_OFFSET
|
|
|
246e17 |
+ jz L(no_shstk)
|
|
|
246e17 |
+
|
|
|
246e17 |
+ /* Save EAX in EDX. */
|
|
|
246e17 |
+ movl %eax, %edx
|
|
|
246e17 |
+
|
|
|
246e17 |
+ xorl %eax, %eax
|
|
|
246e17 |
+ cmpl %gs:SSP_BASE_OFFSET, %eax
|
|
|
246e17 |
+ jnz L(shadow_stack_bound_recorded)
|
|
|
246e17 |
+
|
|
|
246e17 |
+ /* Save EBX in the first scratch register slot. */
|
|
|
246e17 |
+ movl %ebx, oSCRATCH1(%edx)
|
|
|
246e17 |
+
|
|
|
246e17 |
+ /* Get the base address and size of the default shadow stack
|
|
|
246e17 |
+ which must be the current shadow stack since nothing has
|
|
|
246e17 |
+ been recorded yet. */
|
|
|
246e17 |
+ sub $24, %esp
|
|
|
246e17 |
+ mov %esp, %ecx
|
|
|
246e17 |
+ movl $ARCH_CET_STATUS, %ebx
|
|
|
246e17 |
+ movl $__NR_arch_prctl, %eax
|
|
|
246e17 |
+ ENTER_KERNEL
|
|
|
246e17 |
+ testl %eax, %eax
|
|
|
246e17 |
+ jz L(continue_no_err)
|
|
|
246e17 |
+
|
|
|
246e17 |
+ /* This should never happen. */
|
|
|
246e17 |
+ hlt
|
|
|
246e17 |
+
|
|
|
246e17 |
+L(continue_no_err):
|
|
|
246e17 |
+ /* Restore EBX from the first scratch register slot. */
|
|
|
246e17 |
+ movl oSCRATCH1(%edx), %ebx
|
|
|
246e17 |
+
|
|
|
246e17 |
+ /* Record the base of the current shadow stack. */
|
|
|
246e17 |
+ movl 8(%esp), %eax
|
|
|
246e17 |
+ movl %eax, %gs:SSP_BASE_OFFSET
|
|
|
246e17 |
+ add $24, %esp
|
|
|
246e17 |
+
|
|
|
246e17 |
+L(shadow_stack_bound_recorded):
|
|
|
246e17 |
+ /* Load address of the context data structure. */
|
|
|
246e17 |
+ movl 4(%esp), %eax
|
|
|
246e17 |
+
|
|
|
246e17 |
+ /* Get the current shadow stack pointer. */
|
|
|
246e17 |
+ rdsspd %edx
|
|
|
246e17 |
+ /* NB: Save the caller's shadow stack so that we can jump back
|
|
|
246e17 |
+ to the caller directly. */
|
|
|
246e17 |
+ addl $4, %edx
|
|
|
246e17 |
+ movl %edx, oSSP(%eax)
|
|
|
246e17 |
+
|
|
|
246e17 |
+ /* Save the current shadow stack base in ucontext. */
|
|
|
246e17 |
+ movl %gs:SSP_BASE_OFFSET, %edx
|
|
|
246e17 |
+ movl %edx, (oSSP + 4)(%eax)
|
|
|
246e17 |
+
|
|
|
246e17 |
+L(no_shstk):
|
|
|
246e17 |
+#endif
|
|
|
246e17 |
/* We have separate floating-point register content memory on the
|
|
|
246e17 |
stack. We use the __fpregs_mem block in the context. Set the
|
|
|
246e17 |
links up correctly. */
|
|
|
246e17 |
diff --git a/sysdeps/unix/sysv/linux/i386/makecontext.S b/sysdeps/unix/sysv/linux/i386/makecontext.S
|
|
|
246e17 |
index e3ca3dc..2d82ddc 100644
|
|
|
246e17 |
--- a/sysdeps/unix/sysv/linux/i386/makecontext.S
|
|
|
246e17 |
+++ b/sysdeps/unix/sysv/linux/i386/makecontext.S
|
|
|
246e17 |
@@ -18,6 +18,7 @@
|
|
|
246e17 |
<http://www.gnu.org/licenses/>. */
|
|
|
246e17 |
|
|
|
246e17 |
#include <sysdep.h>
|
|
|
246e17 |
+#include <asm/prctl.h>
|
|
|
246e17 |
|
|
|
246e17 |
#include "ucontext_i.h"
|
|
|
246e17 |
|
|
|
246e17 |
@@ -68,6 +69,127 @@ ENTRY(__makecontext)
|
|
|
246e17 |
jnz 1b
|
|
|
246e17 |
2:
|
|
|
246e17 |
|
|
|
246e17 |
+#if SHSTK_ENABLED
|
|
|
246e17 |
+ /* Check if Shadow Stack is enabled. */
|
|
|
246e17 |
+ testl $X86_FEATURE_1_SHSTK, %gs:FEATURE_1_OFFSET
|
|
|
246e17 |
+ jz L(skip_ssp)
|
|
|
246e17 |
+
|
|
|
246e17 |
+ /* Reload the pointer to ucontext. */
|
|
|
246e17 |
+ movl 4(%esp), %eax
|
|
|
246e17 |
+
|
|
|
246e17 |
+ /* Shadow stack is enabled. We need to allocate a new shadow
|
|
|
246e17 |
+ stack. */
|
|
|
246e17 |
+ subl oSS_SP(%eax), %edx
|
|
|
246e17 |
+ shrl $STACK_SIZE_TO_SHADOW_STACK_SIZE_SHIFT, %edx
|
|
|
246e17 |
+
|
|
|
246e17 |
+ /* Align shadow stack size to 8 bytes. */
|
|
|
246e17 |
+ addl $7, %edx
|
|
|
246e17 |
+ andl $-8, %edx
|
|
|
246e17 |
+
|
|
|
246e17 |
+ /* Store shadow stack size in __ssp[2]. */
|
|
|
246e17 |
+ movl %edx, (oSSP + 8)(%eax)
|
|
|
246e17 |
+
|
|
|
246e17 |
+ /* Save ESI in the second scratch register slot. */
|
|
|
246e17 |
+ movl %esi, oSCRATCH2(%eax)
|
|
|
246e17 |
+ /* Save EDI in the third scratch register slot. */
|
|
|
246e17 |
+ movl %edi, oSCRATCH3(%eax)
|
|
|
246e17 |
+
|
|
|
246e17 |
+ /* Save the pointer to ucontext. */
|
|
|
246e17 |
+ movl %eax, %edi
|
|
|
246e17 |
+
|
|
|
246e17 |
+ /* Get the original shadow stack pointer. */
|
|
|
246e17 |
+ rdsspd %esi
|
|
|
246e17 |
+
|
|
|
246e17 |
+ /* Align the saved original shadow stack pointer to the next
|
|
|
246e17 |
+ 8 byte aligned boundary. */
|
|
|
246e17 |
+ andl $-8, %esi
|
|
|
246e17 |
+
|
|
|
246e17 |
+ /* Load the top of the new stack into EDX. */
|
|
|
246e17 |
+ movl oESP(%eax), %edx
|
|
|
246e17 |
+
|
|
|
246e17 |
+ /* We need to terminate the FDE here because the unwinder looks
|
|
|
246e17 |
+ at ra-1 for unwind information. */
|
|
|
246e17 |
+ cfi_endproc
|
|
|
246e17 |
+
|
|
|
246e17 |
+ /* Swap the original stack pointer with the top of the new
|
|
|
246e17 |
+ stack. */
|
|
|
246e17 |
+ xchgl %esp, %edx
|
|
|
246e17 |
+
|
|
|
246e17 |
+ /* Add 4 bytes since CALL will push the 4-byte return address
|
|
|
246e17 |
+ onto stack. */
|
|
|
246e17 |
+ addl $4, %esp
|
|
|
246e17 |
+
|
|
|
246e17 |
+ /* Allocate the new shadow stack. Save EBX in the first scratch
|
|
|
246e17 |
+ register slot. */
|
|
|
246e17 |
+ movl %ebx, oSCRATCH1(%eax)
|
|
|
246e17 |
+
|
|
|
246e17 |
+ /* CET syscall takes 64-bit sizes. */
|
|
|
246e17 |
+ subl $16, %esp
|
|
|
246e17 |
+ movl (oSSP + 8)(%eax), %ecx
|
|
|
246e17 |
+ movl %ecx, (%esp)
|
|
|
246e17 |
+ movl $0, 4(%esp)
|
|
|
246e17 |
+ movl %ecx, 8(%esp)
|
|
|
246e17 |
+ movl $0, 12(%esp)
|
|
|
246e17 |
+ movl %esp, %ecx
|
|
|
246e17 |
+
|
|
|
246e17 |
+ movl $ARCH_CET_ALLOC_SHSTK, %ebx
|
|
|
246e17 |
+ movl $__NR_arch_prctl, %eax
|
|
|
246e17 |
+ ENTER_KERNEL
|
|
|
246e17 |
+ testl %eax, %eax
|
|
|
246e17 |
+ jne L(hlt) /* This should never happen. */
|
|
|
246e17 |
+
|
|
|
246e17 |
+ /* Copy the base address of the new shadow stack to __ssp[1]. */
|
|
|
246e17 |
+ movl (%esp), %eax
|
|
|
246e17 |
+ movl %eax, (oSSP + 4)(%edi)
|
|
|
246e17 |
+
|
|
|
246e17 |
+ addl $16, %esp
|
|
|
246e17 |
+
|
|
|
246e17 |
+ /* Restore EBX from the first scratch register slot. */
|
|
|
246e17 |
+ movl oSCRATCH1(%edi), %ebx
|
|
|
246e17 |
+
|
|
|
246e17 |
+ /* Get the size of the new shadow stack. */
|
|
|
246e17 |
+ movl (oSSP + 8)(%edi), %ecx
|
|
|
246e17 |
+
|
|
|
246e17 |
+ /* Use the restore stoken to restore the new shadow stack. */
|
|
|
246e17 |
+ rstorssp -8(%eax, %ecx)
|
|
|
246e17 |
+
|
|
|
246e17 |
+ /* Save the restore token at the next 8 byte aligned boundary
|
|
|
246e17 |
+ on the original shadow stack. */
|
|
|
246e17 |
+ saveprevssp
|
|
|
246e17 |
+
|
|
|
246e17 |
+ /* Push the address of "jmp exitcode" onto the new stack as
|
|
|
246e17 |
+ well as the new shadow stack. */
|
|
|
246e17 |
+ call 1f
|
|
|
246e17 |
+ jmp L(exitcode)
|
|
|
246e17 |
+1:
|
|
|
246e17 |
+
|
|
|
246e17 |
+ /* Get the new shadow stack pointer. */
|
|
|
246e17 |
+ rdsspd %eax
|
|
|
246e17 |
+
|
|
|
246e17 |
+ /* Use the restore stoken to restore the original shadow stack. */
|
|
|
246e17 |
+ rstorssp -8(%esi)
|
|
|
246e17 |
+
|
|
|
246e17 |
+ /* Save the restore token on the new shadow stack. */
|
|
|
246e17 |
+ saveprevssp
|
|
|
246e17 |
+
|
|
|
246e17 |
+ /* Store the new shadow stack pointer in __ssp[0]. */
|
|
|
246e17 |
+ movl %eax, oSSP(%edi)
|
|
|
246e17 |
+
|
|
|
246e17 |
+ /* Restore the original stack. */
|
|
|
246e17 |
+ mov %edx, %esp
|
|
|
246e17 |
+
|
|
|
246e17 |
+ cfi_startproc
|
|
|
246e17 |
+
|
|
|
246e17 |
+ /* Restore ESI from the second scratch register slot. */
|
|
|
246e17 |
+ movl oSCRATCH2(%edi), %esi
|
|
|
246e17 |
+ /* Restore EDI from the third scratch register slot. */
|
|
|
246e17 |
+ movl oSCRATCH3(%edi), %edi
|
|
|
246e17 |
+
|
|
|
246e17 |
+ ret
|
|
|
246e17 |
+
|
|
|
246e17 |
+L(skip_ssp):
|
|
|
246e17 |
+#endif
|
|
|
246e17 |
+
|
|
|
246e17 |
/* If the function we call returns we must continue with the
|
|
|
246e17 |
context which is given in the uc_link element. To do this
|
|
|
246e17 |
set the return address for the function the user provides
|
|
|
246e17 |
@@ -123,6 +245,7 @@ L(call_exit):
|
|
|
246e17 |
call HIDDEN_JUMPTARGET(exit)
|
|
|
246e17 |
/* The 'exit' call should never return. In case it does cause
|
|
|
246e17 |
the process to terminate. */
|
|
|
246e17 |
+L(hlt):
|
|
|
246e17 |
hlt
|
|
|
246e17 |
cfi_startproc
|
|
|
246e17 |
END(__makecontext)
|
|
|
246e17 |
diff --git a/sysdeps/unix/sysv/linux/i386/setcontext.S b/sysdeps/unix/sysv/linux/i386/setcontext.S
|
|
|
246e17 |
index 7565d7d..7b58918 100644
|
|
|
246e17 |
--- a/sysdeps/unix/sysv/linux/i386/setcontext.S
|
|
|
246e17 |
+++ b/sysdeps/unix/sysv/linux/i386/setcontext.S
|
|
|
246e17 |
@@ -18,6 +18,7 @@
|
|
|
246e17 |
<http://www.gnu.org/licenses/>. */
|
|
|
246e17 |
|
|
|
246e17 |
#include <sysdep.h>
|
|
|
246e17 |
+#include <asm/prctl.h>
|
|
|
246e17 |
|
|
|
246e17 |
#include "ucontext_i.h"
|
|
|
246e17 |
|
|
|
246e17 |
@@ -56,9 +57,6 @@ ENTRY(__setcontext)
|
|
|
246e17 |
movl oFS(%eax), %ecx
|
|
|
246e17 |
movw %cx, %fs
|
|
|
246e17 |
|
|
|
246e17 |
- /* Fetch the address to return to. */
|
|
|
246e17 |
- movl oEIP(%eax), %ecx
|
|
|
246e17 |
-
|
|
|
246e17 |
/* Load the new stack pointer. */
|
|
|
246e17 |
cfi_def_cfa (eax, 0)
|
|
|
246e17 |
cfi_offset (edi, oEDI)
|
|
|
246e17 |
@@ -67,6 +65,103 @@ ENTRY(__setcontext)
|
|
|
246e17 |
cfi_offset (ebx, oEBX)
|
|
|
246e17 |
movl oESP(%eax), %esp
|
|
|
246e17 |
|
|
|
246e17 |
+#if SHSTK_ENABLED
|
|
|
246e17 |
+ /* Check if Shadow Stack is enabled. */
|
|
|
246e17 |
+ testl $X86_FEATURE_1_SHSTK, %gs:FEATURE_1_OFFSET
|
|
|
246e17 |
+ jz L(no_shstk)
|
|
|
246e17 |
+
|
|
|
246e17 |
+ /* If the base of the target shadow stack is the same as the
|
|
|
246e17 |
+ base of the current shadow stack, we unwind the shadow
|
|
|
246e17 |
+ stack. Otherwise it is a stack switch and we look for a
|
|
|
246e17 |
+ restore token. */
|
|
|
246e17 |
+ movl oSSP(%eax), %esi
|
|
|
246e17 |
+ movl %esi, %edi
|
|
|
246e17 |
+
|
|
|
246e17 |
+ /* Get the base of the target shadow stack. */
|
|
|
246e17 |
+ movl (oSSP + 4)(%eax), %ecx
|
|
|
246e17 |
+ cmpl %gs:SSP_BASE_OFFSET, %ecx
|
|
|
246e17 |
+ je L(unwind_shadow_stack)
|
|
|
246e17 |
+
|
|
|
246e17 |
+ /* Align the saved original shadow stack pointer to the next
|
|
|
246e17 |
+ 8 byte aligned boundary. */
|
|
|
246e17 |
+ andl $-8, %esi
|
|
|
246e17 |
+
|
|
|
246e17 |
+L(find_restore_token_loop):
|
|
|
246e17 |
+ /* Look for a restore token. */
|
|
|
246e17 |
+ movl -8(%esi), %ebx
|
|
|
246e17 |
+ andl $-8, %ebx
|
|
|
246e17 |
+ cmpl %esi, %ebx
|
|
|
246e17 |
+ je L(restore_shadow_stack)
|
|
|
246e17 |
+
|
|
|
246e17 |
+ /* Try the next slot. */
|
|
|
246e17 |
+ subl $8, %esi
|
|
|
246e17 |
+ jmp L(find_restore_token_loop)
|
|
|
246e17 |
+
|
|
|
246e17 |
+L(restore_shadow_stack):
|
|
|
246e17 |
+ /* Pop return address from the shadow stack since setcontext
|
|
|
246e17 |
+ will not return. */
|
|
|
246e17 |
+ movl $1, %ebx
|
|
|
246e17 |
+ incsspd %ebx
|
|
|
246e17 |
+
|
|
|
246e17 |
+ /* Use the restore stoken to restore the target shadow stack. */
|
|
|
246e17 |
+ rstorssp -8(%esi)
|
|
|
246e17 |
+
|
|
|
246e17 |
+ /* Save the restore token on the old shadow stack. NB: This
|
|
|
246e17 |
+ restore token may be checked by setcontext or swapcontext
|
|
|
246e17 |
+ later. */
|
|
|
246e17 |
+ saveprevssp
|
|
|
246e17 |
+
|
|
|
246e17 |
+ /* Record the new shadow stack base that was switched to. */
|
|
|
246e17 |
+ movl (oSSP + 4)(%eax), %ebx
|
|
|
246e17 |
+ movl %ebx, %gs:SSP_BASE_OFFSET
|
|
|
246e17 |
+
|
|
|
246e17 |
+L(unwind_shadow_stack):
|
|
|
246e17 |
+ rdsspd %ebx
|
|
|
246e17 |
+ subl %edi, %ebx
|
|
|
246e17 |
+ je L(skip_unwind_shadow_stack)
|
|
|
246e17 |
+ negl %ebx
|
|
|
246e17 |
+ shrl $2, %ebx
|
|
|
246e17 |
+ movl $255, %esi
|
|
|
246e17 |
+L(loop):
|
|
|
246e17 |
+ cmpl %esi, %ebx
|
|
|
246e17 |
+ cmovb %ebx, %esi
|
|
|
246e17 |
+ incsspd %esi
|
|
|
246e17 |
+ subl %esi, %ebx
|
|
|
246e17 |
+ ja L(loop)
|
|
|
246e17 |
+
|
|
|
246e17 |
+L(skip_unwind_shadow_stack):
|
|
|
246e17 |
+
|
|
|
246e17 |
+ /* Load the values of all the preserved registers (except ESP). */
|
|
|
246e17 |
+ movl oEDI(%eax), %edi
|
|
|
246e17 |
+ movl oESI(%eax), %esi
|
|
|
246e17 |
+ movl oEBP(%eax), %ebp
|
|
|
246e17 |
+ movl oEBX(%eax), %ebx
|
|
|
246e17 |
+
|
|
|
246e17 |
+ /* Get the return address set with getcontext. */
|
|
|
246e17 |
+ movl oEIP(%eax), %ecx
|
|
|
246e17 |
+
|
|
|
246e17 |
+ /* Check if return address is valid for the case when setcontext
|
|
|
246e17 |
+ is invoked from L(exitcode) with linked context. */
|
|
|
246e17 |
+ rdsspd %eax
|
|
|
246e17 |
+ cmpl (%eax), %ecx
|
|
|
246e17 |
+ /* Clear EAX to indicate success. NB: Don't use xorl to keep
|
|
|
246e17 |
+ EFLAGS for jne. */
|
|
|
246e17 |
+ movl $0, %eax
|
|
|
246e17 |
+ jne L(jmp)
|
|
|
246e17 |
+ /* Return to the new context if return address valid. */
|
|
|
246e17 |
+ pushl %ecx
|
|
|
246e17 |
+ ret
|
|
|
246e17 |
+
|
|
|
246e17 |
+L(jmp):
|
|
|
246e17 |
+ /* Jump to the new context directly. */
|
|
|
246e17 |
+ jmp *%ecx
|
|
|
246e17 |
+
|
|
|
246e17 |
+L(no_shstk):
|
|
|
246e17 |
+#endif
|
|
|
246e17 |
+
|
|
|
246e17 |
+ /* Fetch the address to return to. */
|
|
|
246e17 |
+ movl oEIP(%eax), %ecx
|
|
|
246e17 |
+
|
|
|
246e17 |
/* Push the return address on the new stack so we can return there. */
|
|
|
246e17 |
pushl %ecx
|
|
|
246e17 |
|
|
|
246e17 |
diff --git a/sysdeps/unix/sysv/linux/i386/swapcontext.S b/sysdeps/unix/sysv/linux/i386/swapcontext.S
|
|
|
246e17 |
index ce27d51..d1b648c 100644
|
|
|
246e17 |
--- a/sysdeps/unix/sysv/linux/i386/swapcontext.S
|
|
|
246e17 |
+++ b/sysdeps/unix/sysv/linux/i386/swapcontext.S
|
|
|
246e17 |
@@ -18,6 +18,7 @@
|
|
|
246e17 |
<http://www.gnu.org/licenses/>. */
|
|
|
246e17 |
|
|
|
246e17 |
#include <sysdep.h>
|
|
|
246e17 |
+#include <asm/prctl.h>
|
|
|
246e17 |
|
|
|
246e17 |
#include "ucontext_i.h"
|
|
|
246e17 |
|
|
|
246e17 |
@@ -76,6 +77,144 @@ ENTRY(__swapcontext)
|
|
|
246e17 |
movl oFS(%eax), %edx
|
|
|
246e17 |
movw %dx, %fs
|
|
|
246e17 |
|
|
|
246e17 |
+#if SHSTK_ENABLED
|
|
|
246e17 |
+ /* Check if Shadow Stack is enabled. */
|
|
|
246e17 |
+ testl $X86_FEATURE_1_SHSTK, %gs:FEATURE_1_OFFSET
|
|
|
246e17 |
+ jz L(no_shstk)
|
|
|
246e17 |
+
|
|
|
246e17 |
+ xorl %eax, %eax
|
|
|
246e17 |
+ cmpl %gs:SSP_BASE_OFFSET, %eax
|
|
|
246e17 |
+ jnz L(shadow_stack_bound_recorded)
|
|
|
246e17 |
+
|
|
|
246e17 |
+ /* Get the base address and size of the default shadow stack
|
|
|
246e17 |
+ which must be the current shadow stack since nothing has
|
|
|
246e17 |
+ been recorded yet. */
|
|
|
246e17 |
+ sub $24, %esp
|
|
|
246e17 |
+ mov %esp, %ecx
|
|
|
246e17 |
+ movl $ARCH_CET_STATUS, %ebx
|
|
|
246e17 |
+ movl $__NR_arch_prctl, %eax
|
|
|
246e17 |
+ ENTER_KERNEL
|
|
|
246e17 |
+ testl %eax, %eax
|
|
|
246e17 |
+ jz L(continue_no_err)
|
|
|
246e17 |
+
|
|
|
246e17 |
+ /* This should never happen. */
|
|
|
246e17 |
+ hlt
|
|
|
246e17 |
+
|
|
|
246e17 |
+L(continue_no_err):
|
|
|
246e17 |
+ /* Record the base of the current shadow stack. */
|
|
|
246e17 |
+ movl 8(%esp), %eax
|
|
|
246e17 |
+ movl %eax, %gs:SSP_BASE_OFFSET
|
|
|
246e17 |
+ add $24, %esp
|
|
|
246e17 |
+
|
|
|
246e17 |
+L(shadow_stack_bound_recorded):
|
|
|
246e17 |
+ /* Load address of the context data structure we save in. */
|
|
|
246e17 |
+ movl 4(%esp), %eax
|
|
|
246e17 |
+
|
|
|
246e17 |
+ /* Load address of the context data structure we swap in */
|
|
|
246e17 |
+ movl 8(%esp), %edx
|
|
|
246e17 |
+
|
|
|
246e17 |
+ /* If we unwind the stack, we can't undo stack unwinding. Just
|
|
|
246e17 |
+ save the target shadow stack pointer as the current shadow
|
|
|
246e17 |
+ stack pointer. */
|
|
|
246e17 |
+ movl oSSP(%edx), %ecx
|
|
|
246e17 |
+ movl %ecx, oSSP(%eax)
|
|
|
246e17 |
+
|
|
|
246e17 |
+ /* Save the current shadow stack base in ucontext. */
|
|
|
246e17 |
+ movl %gs:SSP_BASE_OFFSET, %ecx
|
|
|
246e17 |
+ movl %ecx, (oSSP + 4)(%eax)
|
|
|
246e17 |
+
|
|
|
246e17 |
+ /* If the base of the target shadow stack is the same as the
|
|
|
246e17 |
+ base of the current shadow stack, we unwind the shadow
|
|
|
246e17 |
+ stack. Otherwise it is a stack switch and we look for a
|
|
|
246e17 |
+ restore token. */
|
|
|
246e17 |
+ movl oSSP(%edx), %esi
|
|
|
246e17 |
+ movl %esi, %edi
|
|
|
246e17 |
+
|
|
|
246e17 |
+ /* Get the base of the target shadow stack. */
|
|
|
246e17 |
+ movl (oSSP + 4)(%edx), %ecx
|
|
|
246e17 |
+ cmpl %gs:SSP_BASE_OFFSET, %ecx
|
|
|
246e17 |
+ je L(unwind_shadow_stack)
|
|
|
246e17 |
+
|
|
|
246e17 |
+ /* Align the saved original shadow stack pointer to the next
|
|
|
246e17 |
+ 8 byte aligned boundary. */
|
|
|
246e17 |
+ andl $-8, %esi
|
|
|
246e17 |
+
|
|
|
246e17 |
+L(find_restore_token_loop):
|
|
|
246e17 |
+ /* Look for a restore token. */
|
|
|
246e17 |
+ movl -8(%esi), %ebx
|
|
|
246e17 |
+ andl $-8, %ebx
|
|
|
246e17 |
+ cmpl %esi, %ebx
|
|
|
246e17 |
+ je L(restore_shadow_stack)
|
|
|
246e17 |
+
|
|
|
246e17 |
+ /* Try the next slot. */
|
|
|
246e17 |
+ subl $8, %esi
|
|
|
246e17 |
+ jmp L(find_restore_token_loop)
|
|
|
246e17 |
+
|
|
|
246e17 |
+L(restore_shadow_stack):
|
|
|
246e17 |
+ /* The target shadow stack will be restored. Save the current
|
|
|
246e17 |
+ shadow stack pointer. */
|
|
|
246e17 |
+ rdsspd %ecx
|
|
|
246e17 |
+ movl %ecx, oSSP(%eax)
|
|
|
246e17 |
+
|
|
|
246e17 |
+ /* Use the restore stoken to restore the target shadow stack. */
|
|
|
246e17 |
+ rstorssp -8(%esi)
|
|
|
246e17 |
+
|
|
|
246e17 |
+ /* Save the restore token on the old shadow stack. NB: This
|
|
|
246e17 |
+ restore token may be checked by setcontext or swapcontext
|
|
|
246e17 |
+ later. */
|
|
|
246e17 |
+ saveprevssp
|
|
|
246e17 |
+
|
|
|
246e17 |
+ /* Record the new shadow stack base that was switched to. */
|
|
|
246e17 |
+ movl (oSSP + 4)(%edx), %ebx
|
|
|
246e17 |
+ movl %ebx, %gs:SSP_BASE_OFFSET
|
|
|
246e17 |
+
|
|
|
246e17 |
+L(unwind_shadow_stack):
|
|
|
246e17 |
+ rdsspd %ebx
|
|
|
246e17 |
+ subl %edi, %ebx
|
|
|
246e17 |
+ je L(skip_unwind_shadow_stack)
|
|
|
246e17 |
+ negl %ebx
|
|
|
246e17 |
+ shrl $2, %ebx
|
|
|
246e17 |
+ movl $255, %esi
|
|
|
246e17 |
+L(loop):
|
|
|
246e17 |
+ cmpl %esi, %ebx
|
|
|
246e17 |
+ cmovb %ebx, %esi
|
|
|
246e17 |
+ incsspd %esi
|
|
|
246e17 |
+ subl %esi, %ebx
|
|
|
246e17 |
+ ja L(loop)
|
|
|
246e17 |
+
|
|
|
246e17 |
+L(skip_unwind_shadow_stack):
|
|
|
246e17 |
+
|
|
|
246e17 |
+ /* Load the new stack pointer. */
|
|
|
246e17 |
+ movl oESP(%edx), %esp
|
|
|
246e17 |
+
|
|
|
246e17 |
+ /* Load the values of all the preserved registers (except ESP). */
|
|
|
246e17 |
+ movl oEDI(%edx), %edi
|
|
|
246e17 |
+ movl oESI(%edx), %esi
|
|
|
246e17 |
+ movl oEBP(%edx), %ebp
|
|
|
246e17 |
+ movl oEBX(%edx), %ebx
|
|
|
246e17 |
+
|
|
|
246e17 |
+ /* Get the return address set with getcontext. */
|
|
|
246e17 |
+ movl oEIP(%edx), %ecx
|
|
|
246e17 |
+
|
|
|
246e17 |
+ /* Check if return address is valid for the case when setcontext
|
|
|
246e17 |
+ is invoked from L(exitcode) with linked context. */
|
|
|
246e17 |
+ rdsspd %eax
|
|
|
246e17 |
+ cmpl (%eax), %ecx
|
|
|
246e17 |
+ /* Clear EAX to indicate success. NB: Don't use xorl to keep
|
|
|
246e17 |
+ EFLAGS for jne. */
|
|
|
246e17 |
+ movl $0, %eax
|
|
|
246e17 |
+ jne L(jmp)
|
|
|
246e17 |
+ /* Return to the new context if return address valid. */
|
|
|
246e17 |
+ pushl %ecx
|
|
|
246e17 |
+ ret
|
|
|
246e17 |
+
|
|
|
246e17 |
+L(jmp):
|
|
|
246e17 |
+ /* Jump to the new context directly. */
|
|
|
246e17 |
+ jmp *%ecx
|
|
|
246e17 |
+
|
|
|
246e17 |
+L(no_shstk):
|
|
|
246e17 |
+#endif
|
|
|
246e17 |
+
|
|
|
246e17 |
/* Fetch the address to return to. */
|
|
|
246e17 |
movl oEIP(%eax), %ecx
|
|
|
246e17 |
|
|
|
246e17 |
diff --git a/sysdeps/unix/sysv/linux/i386/sysdep.h b/sysdeps/unix/sysv/linux/i386/sysdep.h
|
|
|
246e17 |
index 3255cc7..9344ac7 100644
|
|
|
246e17 |
--- a/sysdeps/unix/sysv/linux/i386/sysdep.h
|
|
|
246e17 |
+++ b/sysdeps/unix/sysv/linux/i386/sysdep.h
|
|
|
246e17 |
@@ -656,4 +656,9 @@ struct libc_do_syscall_args
|
|
|
246e17 |
# endif
|
|
|
246e17 |
#endif
|
|
|
246e17 |
|
|
|
246e17 |
+/* Each shadow stack slot takes 4 bytes. Assuming that each stack
|
|
|
246e17 |
+ frame takes 128 bytes, this is used to compute shadow stack size
|
|
|
246e17 |
+ from stack size. */
|
|
|
246e17 |
+#define STACK_SIZE_TO_SHADOW_STACK_SIZE_SHIFT 5
|
|
|
246e17 |
+
|
|
|
246e17 |
#endif /* linux/i386/sysdep.h */
|
|
|
246e17 |
diff --git a/sysdeps/unix/sysv/linux/i386/ucontext_i.sym b/sysdeps/unix/sysv/linux/i386/ucontext_i.sym
|
|
|
246e17 |
index 1dfe03d..1d8608e 100644
|
|
|
246e17 |
--- a/sysdeps/unix/sysv/linux/i386/ucontext_i.sym
|
|
|
246e17 |
+++ b/sysdeps/unix/sysv/linux/i386/ucontext_i.sym
|
|
|
246e17 |
@@ -22,6 +22,10 @@ oEBP mreg (EBP)
|
|
|
246e17 |
oESP mreg (ESP)
|
|
|
246e17 |
oEBX mreg (EBX)
|
|
|
246e17 |
oEIP mreg (EIP)
|
|
|
246e17 |
+oSCRATCH1 mreg (EAX)
|
|
|
246e17 |
+oSCRATCH2 mreg (ECX)
|
|
|
246e17 |
+oSCRATCH3 mreg (EDX)
|
|
|
246e17 |
oFPREGS mcontext (fpregs)
|
|
|
246e17 |
oSIGMASK ucontext (uc_sigmask)
|
|
|
246e17 |
oFPREGSMEM ucontext (__fpregs_mem)
|
|
|
246e17 |
+oSSP ucontext (__ssp)
|
|
|
246e17 |
|