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