1/* Install given context. 2 Copyright (C) 2001-2022 Free Software Foundation, Inc. 3 This file is part of the GNU C Library. 4 5 The GNU C Library is free software; you can redistribute it and/or 6 modify it under the terms of the GNU Lesser General Public 7 License as published by the Free Software Foundation; either 8 version 2.1 of the License, or (at your option) any later version. 9 10 The GNU C Library is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 Lesser General Public License for more details. 14 15 You should have received a copy of the GNU Lesser General Public 16 License along with the GNU C Library; if not, see 17 <https://www.gnu.org/licenses/>. */ 18 19#include <sysdep.h> 20#include <asm/prctl.h> 21 22#include "ucontext_i.h" 23 24 25ENTRY(__setcontext) 26 /* Load address of the context data structure. */ 27 movl 4(%esp), %eax 28 29 /* Get the current signal mask. Note that we preserve EBX in case 30 the system call fails and we return from the function with an 31 error. */ 32 pushl %ebx 33 cfi_adjust_cfa_offset (4) 34 xorl %edx, %edx 35 leal oSIGMASK(%eax), %ecx 36 movl $SIG_SETMASK, %ebx 37 cfi_rel_offset (ebx, 0) 38 movl $__NR_sigprocmask, %eax 39 ENTER_KERNEL 40 popl %ebx 41 cfi_adjust_cfa_offset (-4) 42 cfi_restore (ebx) 43 cmpl $-4095, %eax /* Check %eax for error. */ 44 jae SYSCALL_ERROR_LABEL /* Jump to error handler if error. */ 45 46 /* EAX was modified, reload it. */ 47 movl 4(%esp), %eax 48 49 /* Restore the floating-point context. Not the registers, only the 50 rest. */ 51 movl oFPREGS(%eax), %ecx 52 fldenv (%ecx) 53 54 /* Restore the FS segment register. We don't touch the GS register 55 since it is used for threads. */ 56 movl oFS(%eax), %ecx 57 movw %cx, %fs 58 59 /* Load the new stack pointer. */ 60 cfi_def_cfa (eax, 0) 61 cfi_offset (edi, oEDI) 62 cfi_offset (esi, oESI) 63 cfi_offset (ebp, oEBP) 64 cfi_offset (ebx, oEBX) 65 movl oESP(%eax), %esp 66 67#if SHSTK_ENABLED 68 /* Check if Shadow Stack is enabled. */ 69 testl $X86_FEATURE_1_SHSTK, %gs:FEATURE_1_OFFSET 70 jz L(no_shstk) 71 72 /* If the base of the target shadow stack is the same as the 73 base of the current shadow stack, we unwind the shadow 74 stack. Otherwise it is a stack switch and we look for a 75 restore token. */ 76 movl oSSP(%eax), %esi 77 movl %esi, %edi 78 79 /* Get the base of the target shadow stack. */ 80 movl (oSSP + 4)(%eax), %ecx 81 cmpl %gs:SSP_BASE_OFFSET, %ecx 82 je L(unwind_shadow_stack) 83 84 /* Align the saved original shadow stack pointer to the next 85 8 byte aligned boundary. */ 86 andl $-8, %esi 87 88L(find_restore_token_loop): 89 /* Look for a restore token. */ 90 movl -8(%esi), %ebx 91 andl $-8, %ebx 92 cmpl %esi, %ebx 93 je L(restore_shadow_stack) 94 95 /* Try the next slot. */ 96 subl $8, %esi 97 jmp L(find_restore_token_loop) 98 99L(restore_shadow_stack): 100 /* Pop return address from the shadow stack since setcontext 101 will not return. */ 102 movl $1, %ebx 103 incsspd %ebx 104 105 /* Use the restore stoken to restore the target shadow stack. */ 106 rstorssp -8(%esi) 107 108 /* Save the restore token on the old shadow stack. NB: This 109 restore token may be checked by setcontext or swapcontext 110 later. */ 111 saveprevssp 112 113 /* Record the new shadow stack base that was switched to. */ 114 movl (oSSP + 4)(%eax), %ebx 115 movl %ebx, %gs:SSP_BASE_OFFSET 116 117L(unwind_shadow_stack): 118 rdsspd %ebx 119 subl %edi, %ebx 120 je L(skip_unwind_shadow_stack) 121 negl %ebx 122 shrl $2, %ebx 123 movl $255, %esi 124L(loop): 125 cmpl %esi, %ebx 126 cmovb %ebx, %esi 127 incsspd %esi 128 subl %esi, %ebx 129 ja L(loop) 130 131L(skip_unwind_shadow_stack): 132 133 /* Load the values of all the preserved registers (except ESP). */ 134 movl oEDI(%eax), %edi 135 movl oESI(%eax), %esi 136 movl oEBP(%eax), %ebp 137 movl oEBX(%eax), %ebx 138 139 /* Get the return address set with getcontext. */ 140 movl oEIP(%eax), %ecx 141 142 /* Check if return address is valid for the case when setcontext 143 is invoked from L(exitcode) with linked context. */ 144 rdsspd %eax 145 cmpl (%eax), %ecx 146 /* Clear EAX to indicate success. NB: Don't use xorl to keep 147 EFLAGS for jne. */ 148 movl $0, %eax 149 jne L(jmp) 150 /* Return to the new context if return address valid. */ 151 pushl %ecx 152 ret 153 154L(jmp): 155 /* Jump to the new context directly. */ 156 jmp *%ecx 157 158L(no_shstk): 159#endif 160 161 /* Fetch the address to return to. */ 162 movl oEIP(%eax), %ecx 163 164 /* Push the return address on the new stack so we can return there. */ 165 pushl %ecx 166 167 /* Load the values of all the preserved registers (except ESP). */ 168 movl oEDI(%eax), %edi 169 movl oESI(%eax), %esi 170 movl oEBP(%eax), %ebp 171 movl oEBX(%eax), %ebx 172 173 /* All done, return 0 for success. */ 174 xorl %eax, %eax 175 176 /* End FDE here, we fall into another context. */ 177 cfi_endproc 178 cfi_startproc 179 180 /* The following 'ret' will pop the address of the code and jump 181 to it. */ 182 183 ret 184PSEUDO_END(__setcontext) 185libc_hidden_def (__setcontext) 186 187weak_alias (__setcontext, setcontext) 188