1/* Save current context and install the given one. 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(__swapcontext) 26 /* Load address of the context data structure we save in. */ 27 movl 4(%esp), %eax 28 29 /* Save the preserved register values and the return address. */ 30 movl %edi, oEDI(%eax) 31 movl %esi, oESI(%eax) 32 movl %ebp, oEBP(%eax) 33 movl (%esp), %ecx 34 movl %ecx, oEIP(%eax) 35 leal 4(%esp), %ecx 36 movl %ecx, oESP(%eax) 37 movl %ebx, oEBX(%eax) 38 39 /* Save the FS segment register. */ 40 xorl %edx, %edx 41 movw %fs, %dx 42 movl %edx, oFS(%eax) 43 44 /* We have separate floating-point register content memory on the 45 stack. We use the __fpregs_mem block in the context. Set the 46 links up correctly. */ 47 leal oFPREGSMEM(%eax), %ecx 48 movl %ecx, oFPREGS(%eax) 49 /* Save the floating-point context. */ 50 fnstenv (%ecx) 51 52 /* Load address of the context data structure we have to load. */ 53 movl 8(%esp), %ecx 54 55 /* Save the current signal mask and install the new one. */ 56 pushl %ebx 57 leal oSIGMASK(%eax), %edx 58 leal oSIGMASK(%ecx), %ecx 59 movl $SIG_SETMASK, %ebx 60 movl $__NR_sigprocmask, %eax 61 ENTER_KERNEL 62 popl %ebx 63 cmpl $-4095, %eax /* Check %eax for error. */ 64 jae SYSCALL_ERROR_LABEL /* Jump to error handler if error. */ 65 66 /* EAX was modified, reload it. */ 67 movl 8(%esp), %eax 68 69 /* Restore the floating-point context. Not the registers, only the 70 rest. */ 71 movl oFPREGS(%eax), %ecx 72 fldenv (%ecx) 73 74 /* Restore the FS segment register. We don't touch the GS register 75 since it is used for threads. */ 76 movl oFS(%eax), %edx 77 movw %dx, %fs 78 79#if SHSTK_ENABLED 80 /* Check if Shadow Stack is enabled. */ 81 testl $X86_FEATURE_1_SHSTK, %gs:FEATURE_1_OFFSET 82 jz L(no_shstk) 83 84 xorl %eax, %eax 85 cmpl %gs:SSP_BASE_OFFSET, %eax 86 jnz L(shadow_stack_bound_recorded) 87 88 /* Get the base address and size of the default shadow stack 89 which must be the current shadow stack since nothing has 90 been recorded yet. */ 91 sub $24, %esp 92 mov %esp, %ecx 93 movl $ARCH_CET_STATUS, %ebx 94 movl $__NR_arch_prctl, %eax 95 ENTER_KERNEL 96 testl %eax, %eax 97 jz L(continue_no_err) 98 99 /* This should never happen. */ 100 hlt 101 102L(continue_no_err): 103 /* Record the base of the current shadow stack. */ 104 movl 8(%esp), %eax 105 movl %eax, %gs:SSP_BASE_OFFSET 106 add $24, %esp 107 108L(shadow_stack_bound_recorded): 109 /* Load address of the context data structure we save in. */ 110 movl 4(%esp), %eax 111 112 /* Load address of the context data structure we swap in */ 113 movl 8(%esp), %edx 114 115 /* If we unwind the stack, we can't undo stack unwinding. Just 116 save the target shadow stack pointer as the current shadow 117 stack pointer. */ 118 movl oSSP(%edx), %ecx 119 movl %ecx, oSSP(%eax) 120 121 /* Save the current shadow stack base in ucontext. */ 122 movl %gs:SSP_BASE_OFFSET, %ecx 123 movl %ecx, (oSSP + 4)(%eax) 124 125 /* If the base of the target shadow stack is the same as the 126 base of the current shadow stack, we unwind the shadow 127 stack. Otherwise it is a stack switch and we look for a 128 restore token. */ 129 movl oSSP(%edx), %esi 130 movl %esi, %edi 131 132 /* Get the base of the target shadow stack. */ 133 movl (oSSP + 4)(%edx), %ecx 134 cmpl %gs:SSP_BASE_OFFSET, %ecx 135 je L(unwind_shadow_stack) 136 137 /* Align the saved original shadow stack pointer to the next 138 8 byte aligned boundary. */ 139 andl $-8, %esi 140 141L(find_restore_token_loop): 142 /* Look for a restore token. */ 143 movl -8(%esi), %ebx 144 andl $-8, %ebx 145 cmpl %esi, %ebx 146 je L(restore_shadow_stack) 147 148 /* Try the next slot. */ 149 subl $8, %esi 150 jmp L(find_restore_token_loop) 151 152L(restore_shadow_stack): 153 /* The target shadow stack will be restored. Save the current 154 shadow stack pointer. */ 155 rdsspd %ecx 156 movl %ecx, oSSP(%eax) 157 158 /* Use the restore stoken to restore the target shadow stack. */ 159 rstorssp -8(%esi) 160 161 /* Save the restore token on the old shadow stack. NB: This 162 restore token may be checked by setcontext or swapcontext 163 later. */ 164 saveprevssp 165 166 /* Record the new shadow stack base that was switched to. */ 167 movl (oSSP + 4)(%edx), %ebx 168 movl %ebx, %gs:SSP_BASE_OFFSET 169 170L(unwind_shadow_stack): 171 rdsspd %ebx 172 subl %edi, %ebx 173 je L(skip_unwind_shadow_stack) 174 negl %ebx 175 shrl $2, %ebx 176 movl $255, %esi 177L(loop): 178 cmpl %esi, %ebx 179 cmovb %ebx, %esi 180 incsspd %esi 181 subl %esi, %ebx 182 ja L(loop) 183 184L(skip_unwind_shadow_stack): 185 186 /* Load the new stack pointer. */ 187 movl oESP(%edx), %esp 188 189 /* Load the values of all the preserved registers (except ESP). */ 190 movl oEDI(%edx), %edi 191 movl oESI(%edx), %esi 192 movl oEBP(%edx), %ebp 193 movl oEBX(%edx), %ebx 194 195 /* Get the return address set with getcontext. */ 196 movl oEIP(%edx), %ecx 197 198 /* Check if return address is valid for the case when setcontext 199 is invoked from L(exitcode) with linked context. */ 200 rdsspd %eax 201 cmpl (%eax), %ecx 202 /* Clear EAX to indicate success. NB: Don't use xorl to keep 203 EFLAGS for jne. */ 204 movl $0, %eax 205 jne L(jmp) 206 /* Return to the new context if return address valid. */ 207 pushl %ecx 208 ret 209 210L(jmp): 211 /* Jump to the new context directly. */ 212 jmp *%ecx 213 214L(no_shstk): 215#endif 216 217 /* Fetch the address to return to. */ 218 movl oEIP(%eax), %ecx 219 220 /* Load the new stack pointer. */ 221 movl oESP(%eax), %esp 222 223 /* Push the return address on the new stack so we can return there. */ 224 pushl %ecx 225 226 /* Load the values of all the preserved registers (except ESP). */ 227 movl oEDI(%eax), %edi 228 movl oESI(%eax), %esi 229 movl oEBP(%eax), %ebp 230 movl oEBX(%eax), %ebx 231 232 /* All done, return 0 for success. */ 233 xorl %eax, %eax 234 235 /* The following 'ret' will pop the address of the code and jump 236 to it. */ 237 ret 238PSEUDO_END(__swapcontext) 239 240weak_alias (__swapcontext, swapcontext) 241