| 1 | /* Create new context. | 
|---|
| 2 | Copyright (C) 2002-2020 Free Software Foundation, Inc. | 
|---|
| 3 | This file is part of the GNU C Library. | 
|---|
| 4 | Contributed by Andreas Jaeger <aj@suse.de>, 2002. | 
|---|
| 5 |  | 
|---|
| 6 | The GNU C Library is free software; you can redistribute it and/or | 
|---|
| 7 | modify it under the terms of the GNU Lesser General Public | 
|---|
| 8 | License as published by the Free Software Foundation; either | 
|---|
| 9 | version 2.1 of the License, or (at your option) any later version. | 
|---|
| 10 |  | 
|---|
| 11 | The GNU C Library is distributed in the hope that it will be useful, | 
|---|
| 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|---|
| 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
|---|
| 14 | Lesser General Public License for more details. | 
|---|
| 15 |  | 
|---|
| 16 | You should have received a copy of the GNU Lesser General Public | 
|---|
| 17 | License along with the GNU C Library; if not, see | 
|---|
| 18 | <https://www.gnu.org/licenses/>.  */ | 
|---|
| 19 |  | 
|---|
| 20 | #include <sysdep.h> | 
|---|
| 21 | #include <stdarg.h> | 
|---|
| 22 | #include <stdint.h> | 
|---|
| 23 | #include <ucontext.h> | 
|---|
| 24 | #if SHSTK_ENABLED | 
|---|
| 25 | # include <pthread.h> | 
|---|
| 26 | # include <libc-pointer-arith.h> | 
|---|
| 27 | # include <sys/prctl.h> | 
|---|
| 28 | #endif | 
|---|
| 29 |  | 
|---|
| 30 | #include "ucontext_i.h" | 
|---|
| 31 |  | 
|---|
| 32 | /* This implementation can handle any ARGC value but only | 
|---|
| 33 | normal integer parameters. | 
|---|
| 34 | makecontext sets up a stack and the registers for the | 
|---|
| 35 | user context. The stack looks like this: | 
|---|
| 36 | +-----------------------+ | 
|---|
| 37 | | next context          | | 
|---|
| 38 | +-----------------------+ | 
|---|
| 39 | | parameter 7-n         | | 
|---|
| 40 | +-----------------------+ | 
|---|
| 41 | | trampoline address    | | 
|---|
| 42 | %rsp ->    +-----------------------+ | 
|---|
| 43 |  | 
|---|
| 44 | The registers are set up like this: | 
|---|
| 45 | %rdi,%rsi,%rdx,%rcx,%r8,%r9: parameter 1 to 6 | 
|---|
| 46 | %rbx   : address of next context | 
|---|
| 47 | %rsp   : stack pointer. | 
|---|
| 48 | */ | 
|---|
| 49 |  | 
|---|
| 50 | /* XXX: This implementation currently only handles integer arguments. | 
|---|
| 51 | To handle long int and pointer arguments the va_arg arguments needs | 
|---|
| 52 | to be changed to long and also the stdlib/tst-setcontext.c file needs | 
|---|
| 53 | to be changed to pass long arguments to makecontext.  */ | 
|---|
| 54 |  | 
|---|
| 55 |  | 
|---|
| 56 | void | 
|---|
| 57 | __makecontext (ucontext_t *ucp, void (*func) (void), int argc, ...) | 
|---|
| 58 | { | 
|---|
| 59 | extern void __start_context (void) attribute_hidden; | 
|---|
| 60 | extern void __push___start_context (ucontext_t *) | 
|---|
| 61 | attribute_hidden; | 
|---|
| 62 | greg_t *sp; | 
|---|
| 63 | unsigned int idx_uc_link; | 
|---|
| 64 | va_list ap; | 
|---|
| 65 | int i; | 
|---|
| 66 |  | 
|---|
| 67 | /* Generate room on stack for parameter if needed and uc_link.  */ | 
|---|
| 68 | sp = (greg_t *) ((uintptr_t) ucp->uc_stack.ss_sp | 
|---|
| 69 | + ucp->uc_stack.ss_size); | 
|---|
| 70 | sp -= (argc > 6 ? argc - 6 : 0) + 1; | 
|---|
| 71 | /* Align stack and make space for trampoline address.  */ | 
|---|
| 72 | sp = (greg_t *) ((((uintptr_t) sp) & -16L) - 8); | 
|---|
| 73 |  | 
|---|
| 74 | idx_uc_link = (argc > 6 ? argc - 6 : 0) + 1; | 
|---|
| 75 |  | 
|---|
| 76 | /* Setup context ucp.  */ | 
|---|
| 77 | /* Address to jump to.  */ | 
|---|
| 78 | ucp->uc_mcontext.gregs[REG_RIP] = (uintptr_t) func; | 
|---|
| 79 | /* Setup rbx.*/ | 
|---|
| 80 | ucp->uc_mcontext.gregs[REG_RBX] = (uintptr_t) &sp[idx_uc_link]; | 
|---|
| 81 | ucp->uc_mcontext.gregs[REG_RSP] = (uintptr_t) sp; | 
|---|
| 82 |  | 
|---|
| 83 | /* Setup stack.  */ | 
|---|
| 84 | #if SHSTK_ENABLED | 
|---|
| 85 | struct pthread *self = THREAD_SELF; | 
|---|
| 86 | unsigned int feature_1 = THREAD_GETMEM (self, header.feature_1); | 
|---|
| 87 | /* NB: We must check feature_1 before accessing __ssp since caller | 
|---|
| 88 | may be compiled against ucontext_t without __ssp.  */ | 
|---|
| 89 | if ((feature_1 & X86_FEATURE_1_SHSTK) != 0) | 
|---|
| 90 | { | 
|---|
| 91 | /* Shadow stack is enabled.  We need to allocate a new shadow | 
|---|
| 92 | stack.  */ | 
|---|
| 93 | unsigned long ssp_size = (((uintptr_t) sp | 
|---|
| 94 | - (uintptr_t) ucp->uc_stack.ss_sp) | 
|---|
| 95 | >> STACK_SIZE_TO_SHADOW_STACK_SIZE_SHIFT); | 
|---|
| 96 | /* Align shadow stack to 8 bytes.  */ | 
|---|
| 97 | ssp_size = ALIGN_UP (ssp_size, 8); | 
|---|
| 98 |  | 
|---|
| 99 | ucp->__ssp[1] = ssp_size; | 
|---|
| 100 | ucp->__ssp[2] = ssp_size; | 
|---|
| 101 |  | 
|---|
| 102 | /* Call __push___start_context to allocate a new shadow stack, | 
|---|
| 103 | push __start_context onto the new stack as well as the new | 
|---|
| 104 | shadow stack.  NB: After __push___start_context returns, | 
|---|
| 105 | ucp->__ssp[0]: The new shadow stack pointer. | 
|---|
| 106 | ucp->__ssp[1]: The base address of the new shadow stack. | 
|---|
| 107 | ucp->__ssp[2]: The size of the new shadow stack. | 
|---|
| 108 | */ | 
|---|
| 109 | __push___start_context (ucp); | 
|---|
| 110 | } | 
|---|
| 111 | else | 
|---|
| 112 | #endif | 
|---|
| 113 | sp[0] = (uintptr_t) &__start_context; | 
|---|
| 114 | sp[idx_uc_link] = (uintptr_t) ucp->uc_link; | 
|---|
| 115 |  | 
|---|
| 116 | va_start (ap, argc); | 
|---|
| 117 | /* Handle arguments. | 
|---|
| 118 |  | 
|---|
| 119 | The standard says the parameters must all be int values.  This is | 
|---|
| 120 | an historic accident and would be done differently today.  For | 
|---|
| 121 | x86-64 all integer values are passed as 64-bit values and | 
|---|
| 122 | therefore extending the API to copy 64-bit values instead of | 
|---|
| 123 | 32-bit ints makes sense.  It does not break existing | 
|---|
| 124 | functionality and it does not violate the standard which says | 
|---|
| 125 | that passing non-int values means undefined behavior.  */ | 
|---|
| 126 | for (i = 0; i < argc; ++i) | 
|---|
| 127 | switch (i) | 
|---|
| 128 | { | 
|---|
| 129 | case 0: | 
|---|
| 130 | ucp->uc_mcontext.gregs[REG_RDI] = va_arg (ap, greg_t); | 
|---|
| 131 | break; | 
|---|
| 132 | case 1: | 
|---|
| 133 | ucp->uc_mcontext.gregs[REG_RSI] = va_arg (ap, greg_t); | 
|---|
| 134 | break; | 
|---|
| 135 | case 2: | 
|---|
| 136 | ucp->uc_mcontext.gregs[REG_RDX] = va_arg (ap, greg_t); | 
|---|
| 137 | break; | 
|---|
| 138 | case 3: | 
|---|
| 139 | ucp->uc_mcontext.gregs[REG_RCX] = va_arg (ap, greg_t); | 
|---|
| 140 | break; | 
|---|
| 141 | case 4: | 
|---|
| 142 | ucp->uc_mcontext.gregs[REG_R8] = va_arg (ap, greg_t); | 
|---|
| 143 | break; | 
|---|
| 144 | case 5: | 
|---|
| 145 | ucp->uc_mcontext.gregs[REG_R9] = va_arg (ap, greg_t); | 
|---|
| 146 | break; | 
|---|
| 147 | default: | 
|---|
| 148 | /* Put value on stack.  */ | 
|---|
| 149 | sp[i - 5] = va_arg (ap, greg_t); | 
|---|
| 150 | break; | 
|---|
| 151 | } | 
|---|
| 152 | va_end (ap); | 
|---|
| 153 |  | 
|---|
| 154 | } | 
|---|
| 155 |  | 
|---|
| 156 |  | 
|---|
| 157 | weak_alias (__makecontext, makecontext) | 
|---|
| 158 |  | 
|---|