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
25ENTRY(__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
651: movl 12(%esp,%ecx,4), %eax
66 movl %eax, (%edx,%ecx,4)
67 decl %ecx
68 jnz 1b
692:
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)
1631:
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
189L(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)
2001: 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. */
220L(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
2342:
235 /* Exit with status 0. */
236 xorl %eax, %eax
237
238L(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. */
247L(hlt):
248 hlt
249 cfi_startproc
250END(__makecontext)
251
252weak_alias (__makecontext, makecontext)
253

source code of glibc/sysdeps/unix/sysv/linux/i386/makecontext.S