1 | /* Copyright (C) 2002-2024 Free Software Foundation, Inc. |
2 | This file is part of the GNU C Library. |
3 | |
4 | The GNU C Library is free software; you can redistribute it and/or |
5 | modify it under the terms of the GNU Lesser General Public |
6 | License as published by the Free Software Foundation; either |
7 | version 2.1 of the License, or (at your option) any later version. |
8 | |
9 | The GNU C Library is distributed in the hope that it will be useful, |
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
12 | Lesser General Public License for more details. |
13 | |
14 | You should have received a copy of the GNU Lesser General Public |
15 | License along with the GNU C Library; if not, see |
16 | <https://www.gnu.org/licenses/>. */ |
17 | |
18 | #include <sysdep.h> |
19 | |
20 | #if SHSTK_ENABLED |
21 | # include <asm/prctl.h> |
22 | # include "ucontext_i.h" |
23 | |
24 | /* Use CALL to push __start_context onto the new stack as well as the new |
25 | shadow stack. RDI points to ucontext: |
26 | Incoming: |
27 | __ssp[0]: The new shadow stack pointer. |
28 | __ssp[1]: The base address of the new shadow stack. |
29 | __ssp[2]: The size of the new shadow stack. |
30 | */ |
31 | |
32 | ENTRY(__push___start_context) |
33 | /* Get the original shadow stack pointer. */ |
34 | rdsspq %rcx |
35 | /* Save the original stack pointer. */ |
36 | movq %rsp, %rdx |
37 | /* Load the top of the new stack into RSI. */ |
38 | movq oRSP(%rdi), %rsi |
39 | /* Add 8 bytes to RSI since CALL will push the 8-byte return |
40 | address onto stack. */ |
41 | leaq 8(%rsi), %rsp |
42 | /* The size of the new shadow stack is stored in __ssp[2]. */ |
43 | mov (oSSP + 16)(%rdi), %RSI_LP |
44 | /* The new shadow stack base is stored in __ssp[1]. */ |
45 | mov (oSSP + 8)(%rdi), %RAX_LP |
46 | /* Use the restore stoken to restore the new shadow stack. */ |
47 | rstorssp -8(%rax, %rsi) |
48 | |
49 | /* Save the restore token on the original shadow stack. */ |
50 | saveprevssp |
51 | |
52 | /* Push the address of "jmp __start_context" onto the new stack |
53 | as well as the new shadow stack. */ |
54 | call 1f |
55 | jmp __start_context |
56 | 1: |
57 | |
58 | /* Use the restore stoken to restore the original shadow stack. */ |
59 | rstorssp -8(%rcx) |
60 | |
61 | /* Save the restore token on the new shadow stack. */ |
62 | saveprevssp |
63 | |
64 | /* Restore the original stack. */ |
65 | mov %rdx, %rsp |
66 | ret |
67 | END(__push___start_context) |
68 | #endif |
69 | |
70 | /* This is the helper code which gets called if a function which is |
71 | registered with 'makecontext' returns. In this case we have to |
72 | install the context listed in the uc_link element of the context |
73 | 'makecontext' manipulated at the time of the 'makecontext' call. |
74 | If the pointer is NULL the process must terminate. */ |
75 | |
76 | |
77 | ENTRY(__start_context) |
78 | /* This removes the parameters passed to the function given to |
79 | 'makecontext' from the stack. RBX contains the address |
80 | on the stack pointer for the next context. */ |
81 | movq %rbx, %rsp |
82 | |
83 | /* Don't use pop here so that stack is aligned to 16 bytes. */ |
84 | movq (%rsp), %rdi /* This is the next context. */ |
85 | testq %rdi, %rdi |
86 | je 2f /* If it is zero exit. */ |
87 | |
88 | call __setcontext |
89 | /* If this returns (which can happen if the syscall fails) we'll |
90 | exit the program with the return error value (-1). */ |
91 | movq %rax,%rdi |
92 | |
93 | 2: |
94 | call HIDDEN_JUMPTARGET(exit) |
95 | /* The 'exit' call should never return. In case it does cause |
96 | the process to terminate. */ |
97 | L(hlt): |
98 | hlt |
99 | END(__start_context) |
100 | |