1 | /* Create new 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 | |
25 | ENTRY(__makecontext) |
26 | movl 4(%esp), %eax |
27 | |
28 | /* Load the address of the function we are supposed to run. */ |
29 | movl 8(%esp), %ecx |
30 | |
31 | /* Compute the address of the stack. The information comes from |
32 | to us_stack element. */ |
33 | movl oSS_SP(%eax), %edx |
34 | movl %ecx, oEIP(%eax) |
35 | addl oSS_SIZE(%eax), %edx |
36 | |
37 | /* Remember the number of parameters for the exit handler since |
38 | it has to remove them. We store the number in the EBX register |
39 | which the function we will call must preserve. */ |
40 | movl 12(%esp), %ecx |
41 | movl %ecx, oEBX(%eax) |
42 | |
43 | /* Make room on the new stack for the parameters. |
44 | Room for the arguments, return address (== L(exitcode)) and |
45 | oLINK pointer is needed. One of the pointer sizes is subtracted |
46 | after aligning the stack. */ |
47 | negl %ecx |
48 | leal -4(%edx,%ecx,4), %edx |
49 | negl %ecx |
50 | |
51 | /* Align the stack. */ |
52 | andl $0xfffffff0, %edx |
53 | subl $4, %edx |
54 | |
55 | /* Store the future stack pointer. */ |
56 | movl %edx, oESP(%eax) |
57 | |
58 | /* Put the next context on the new stack (from the uc_link |
59 | element). */ |
60 | movl oLINK(%eax), %eax |
61 | movl %eax, 4(%edx,%ecx,4) |
62 | |
63 | /* Copy all the parameters. */ |
64 | jecxz 2f |
65 | 1: movl 12(%esp,%ecx,4), %eax |
66 | movl %eax, (%edx,%ecx,4) |
67 | decl %ecx |
68 | jnz 1b |
69 | 2: |
70 | |
71 | #if SHSTK_ENABLED |
72 | /* Check if Shadow Stack is enabled. */ |
73 | testl $X86_FEATURE_1_SHSTK, %gs:FEATURE_1_OFFSET |
74 | jz L(skip_ssp) |
75 | |
76 | /* Reload the pointer to ucontext. */ |
77 | movl 4(%esp), %eax |
78 | |
79 | /* Shadow stack is enabled. We need to allocate a new shadow |
80 | stack. */ |
81 | subl oSS_SP(%eax), %edx |
82 | shrl $STACK_SIZE_TO_SHADOW_STACK_SIZE_SHIFT, %edx |
83 | |
84 | /* Align shadow stack size to 8 bytes. */ |
85 | addl $7, %edx |
86 | andl $-8, %edx |
87 | |
88 | /* Store shadow stack size in __ssp[2]. */ |
89 | movl %edx, (oSSP + 8)(%eax) |
90 | |
91 | /* Save ESI in the second scratch register slot. */ |
92 | movl %esi, oSCRATCH2(%eax) |
93 | /* Save EDI in the third scratch register slot. */ |
94 | movl %edi, oSCRATCH3(%eax) |
95 | |
96 | /* Save the pointer to ucontext. */ |
97 | movl %eax, %edi |
98 | |
99 | /* Get the original shadow stack pointer. */ |
100 | rdsspd %esi |
101 | |
102 | /* Align the saved original shadow stack pointer to the next |
103 | 8 byte aligned boundary. */ |
104 | andl $-8, %esi |
105 | |
106 | /* Load the top of the new stack into EDX. */ |
107 | movl oESP(%eax), %edx |
108 | |
109 | /* We need to terminate the FDE here because the unwinder looks |
110 | at ra-1 for unwind information. */ |
111 | cfi_endproc |
112 | |
113 | /* Swap the original stack pointer with the top of the new |
114 | stack. */ |
115 | xchgl %esp, %edx |
116 | |
117 | /* Add 4 bytes since CALL will push the 4-byte return address |
118 | onto stack. */ |
119 | addl $4, %esp |
120 | |
121 | /* Allocate the new shadow stack. Save EBX in the first scratch |
122 | register slot. */ |
123 | movl %ebx, oSCRATCH1(%eax) |
124 | |
125 | /* CET syscall takes 64-bit sizes. */ |
126 | subl $16, %esp |
127 | movl (oSSP + 8)(%eax), %ecx |
128 | movl %ecx, (%esp) |
129 | movl $0, 4(%esp) |
130 | movl %ecx, 8(%esp) |
131 | movl $0, 12(%esp) |
132 | movl %esp, %ecx |
133 | |
134 | movl $ARCH_CET_ALLOC_SHSTK, %ebx |
135 | movl $__NR_arch_prctl, %eax |
136 | ENTER_KERNEL |
137 | testl %eax, %eax |
138 | jne L(hlt) /* This should never happen. */ |
139 | |
140 | /* Copy the base address of the new shadow stack to __ssp[1]. */ |
141 | movl (%esp), %eax |
142 | movl %eax, (oSSP + 4)(%edi) |
143 | |
144 | addl $16, %esp |
145 | |
146 | /* Restore EBX from the first scratch register slot. */ |
147 | movl oSCRATCH1(%edi), %ebx |
148 | |
149 | /* Get the size of the new shadow stack. */ |
150 | movl (oSSP + 8)(%edi), %ecx |
151 | |
152 | /* Use the restore stoken to restore the new shadow stack. */ |
153 | rstorssp -8(%eax, %ecx) |
154 | |
155 | /* Save the restore token at the next 8 byte aligned boundary |
156 | on the original shadow stack. */ |
157 | saveprevssp |
158 | |
159 | /* Push the address of "jmp exitcode" onto the new stack as |
160 | well as the new shadow stack. */ |
161 | call 1f |
162 | jmp L(exitcode) |
163 | 1: |
164 | |
165 | /* Get the new shadow stack pointer. */ |
166 | rdsspd %eax |
167 | |
168 | /* Use the restore stoken to restore the original shadow stack. */ |
169 | rstorssp -8(%esi) |
170 | |
171 | /* Save the restore token on the new shadow stack. */ |
172 | saveprevssp |
173 | |
174 | /* Store the new shadow stack pointer in __ssp[0]. */ |
175 | movl %eax, oSSP(%edi) |
176 | |
177 | /* Restore the original stack. */ |
178 | mov %edx, %esp |
179 | |
180 | cfi_startproc |
181 | |
182 | /* Restore ESI from the second scratch register slot. */ |
183 | movl oSCRATCH2(%edi), %esi |
184 | /* Restore EDI from the third scratch register slot. */ |
185 | movl oSCRATCH3(%edi), %edi |
186 | |
187 | ret |
188 | |
189 | L(skip_ssp): |
190 | #endif |
191 | |
192 | /* If the function we call returns we must continue with the |
193 | context which is given in the uc_link element. To do this |
194 | set the return address for the function the user provides |
195 | to a little bit of helper code which does the magic (see |
196 | below). */ |
197 | #ifdef PIC |
198 | call 1f |
199 | cfi_adjust_cfa_offset (4) |
200 | 1: popl %ecx |
201 | cfi_adjust_cfa_offset (-4) |
202 | addl $L(exitcode)-1b, %ecx |
203 | movl %ecx, (%edx) |
204 | #else |
205 | movl $L(exitcode), (%edx) |
206 | #endif |
207 | /* We need to terminate the FDE here instead of after ret because |
208 | the unwinder looks at ra-1 for unwind information. */ |
209 | cfi_endproc |
210 | |
211 | /* 'makecontext' returns no value. */ |
212 | ret |
213 | |
214 | /* This is the helper code which gets called if a function which |
215 | is registered with 'makecontext' returns. In this case we |
216 | have to install the context listed in the uc_link element of |
217 | the context 'makecontext' manipulated at the time of the |
218 | 'makecontext' call. If the pointer is NULL the process must |
219 | terminate. */ |
220 | L(exitcode): |
221 | /* This removes the parameters passed to the function given to |
222 | 'makecontext' from the stack. EBX contains the number of |
223 | parameters (see above). */ |
224 | leal (%esp,%ebx,4), %esp |
225 | |
226 | cmpl $0, (%esp) /* Check the next context. */ |
227 | je 2f /* If it is zero exit. */ |
228 | |
229 | call HIDDEN_JUMPTARGET(__setcontext) |
230 | /* If this returns (which can happen if the syscall fails) we'll |
231 | exit the program with the return error value (-1). */ |
232 | jmp L(call_exit) |
233 | |
234 | 2: |
235 | /* Exit with status 0. */ |
236 | xorl %eax, %eax |
237 | |
238 | L(call_exit): |
239 | /* Align the stack and pass the exit code (from %eax). */ |
240 | andl $0xfffffff0, %esp |
241 | subl $12, %esp |
242 | pushl %eax |
243 | |
244 | call HIDDEN_JUMPTARGET(exit) |
245 | /* The 'exit' call should never return. In case it does cause |
246 | the process to terminate. */ |
247 | L(hlt): |
248 | hlt |
249 | cfi_startproc |
250 | END(__makecontext) |
251 | |
252 | weak_alias (__makecontext, makecontext) |
253 | |