1 | /* Copyright (C) 2001-2023 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 | #include <pointer_guard.h> |
20 | #include <jmpbuf-offsets.h> |
21 | #include <asm-syntax.h> |
22 | #include <stap-probe.h> |
23 | #include <sigaltstack-offsets.h> |
24 | #include <jmp_buf-ssp.h> |
25 | |
26 | /* Don't restore shadow stack register if shadow stack isn't enabled. */ |
27 | #if !SHSTK_ENABLED |
28 | # undef SHADOW_STACK_POINTER_OFFSET |
29 | #endif |
30 | |
31 | .section .rodata.str1.1,"aMS" ,@progbits,1 |
32 | .type longjmp_msg,@object |
33 | longjmp_msg: |
34 | .string "longjmp causes uninitialized stack frame" |
35 | .size longjmp_msg, .-longjmp_msg |
36 | |
37 | |
38 | //#define __longjmp ____longjmp_chk |
39 | |
40 | #ifdef PIC |
41 | # define CALL_FAIL sub $8, %RSP_LP; \ |
42 | cfi_remember_state; \ |
43 | cfi_def_cfa_offset(16); \ |
44 | lea longjmp_msg(%rip), %RDI_LP; \ |
45 | call HIDDEN_JUMPTARGET(__fortify_fail); \ |
46 | nop; \ |
47 | cfi_restore_state |
48 | #else |
49 | # define CALL_FAIL sub $8, %RSP_LP; \ |
50 | cfi_remember_state; \ |
51 | cfi_def_cfa_offset(16); \ |
52 | mov $longjmp_msg, %RDI_LP; \ |
53 | call HIDDEN_JUMPTARGET(__fortify_fail); \ |
54 | nop; \ |
55 | cfi_restore_state |
56 | #endif |
57 | |
58 | /* Jump to the position specified by ENV, causing the |
59 | setjmp call there to return VAL, or 1 if VAL is 0. |
60 | void __longjmp (__jmp_buf env, int val). */ |
61 | .text |
62 | ENTRY(____longjmp_chk) |
63 | /* Restore registers. */ |
64 | mov (JB_RSP*8)(%rdi), %R8_LP |
65 | mov (JB_RBP*8)(%rdi),%R9_LP |
66 | mov (JB_PC*8)(%rdi), %RDX_LP |
67 | #ifdef PTR_DEMANGLE |
68 | PTR_DEMANGLE (%R8_LP) |
69 | PTR_DEMANGLE (%R9_LP) |
70 | PTR_DEMANGLE (%RDX_LP) |
71 | # ifdef __ILP32__ |
72 | /* We ignored the high bits of the %rbp value because only the low |
73 | bits are mangled. But we cannot presume that %rbp is being used |
74 | as a pointer and truncate it, so recover the high bits. */ |
75 | movl (JB_RBP*8 + 4)(%rdi), %eax |
76 | shlq $32, %rax |
77 | orq %rax, %r9 |
78 | # endif |
79 | #endif |
80 | |
81 | cmp %R8_LP, %RSP_LP |
82 | jbe .Lok |
83 | |
84 | /* Save function parameters. */ |
85 | movq %rdi, %r10 |
86 | cfi_register (%rdi, %r10) |
87 | movl %esi, %ebx |
88 | cfi_register (%rsi, %rbx) |
89 | |
90 | xorl %edi, %edi |
91 | lea -sizeSS(%rsp), %RSI_LP |
92 | movl $__NR_sigaltstack, %eax |
93 | syscall |
94 | /* Without working sigaltstack we cannot perform the test. */ |
95 | testl %eax, %eax |
96 | jne .Lok2 |
97 | testl $1, (-sizeSS + oSS_FLAGS)(%rsp) |
98 | jz .Lfail |
99 | |
100 | mov (-sizeSS + oSS_SP)(%rsp), %RAX_LP |
101 | add (-sizeSS + oSS_SIZE)(%rsp), %RAX_LP |
102 | sub %R8_LP, %RAX_LP |
103 | cmp (-sizeSS + oSS_SIZE)(%rsp), %RAX_LP |
104 | jae .Lok2 |
105 | |
106 | .Lfail: CALL_FAIL |
107 | |
108 | .Lok2: movq %r10, %rdi |
109 | cfi_restore (%rdi) |
110 | movl %ebx, %esi |
111 | cfi_restore (%rsi) |
112 | |
113 | .Lok: |
114 | #ifdef SHADOW_STACK_POINTER_OFFSET |
115 | # if IS_IN (libc) && defined SHARED && defined FEATURE_1_OFFSET |
116 | /* Check if Shadow Stack is enabled. */ |
117 | testl $X86_FEATURE_1_SHSTK, %fs:FEATURE_1_OFFSET |
118 | jz L(skip_ssp) |
119 | # else |
120 | xorl %eax, %eax |
121 | # endif |
122 | /* Check and adjust the Shadow-Stack-Pointer. */ |
123 | rdsspq %rax |
124 | /* And compare it with the saved ssp value. */ |
125 | subq SHADOW_STACK_POINTER_OFFSET(%rdi), %rax |
126 | je L(skip_ssp) |
127 | /* Count the number of frames to adjust and adjust it |
128 | with incssp instruction. The instruction can adjust |
129 | the ssp by [0..255] value only thus use a loop if |
130 | the number of frames is bigger than 255. */ |
131 | negq %rax |
132 | shrq $3, %rax |
133 | /* NB: We saved Shadow-Stack-Pointer of setjmp. Since we are |
134 | restoring Shadow-Stack-Pointer of setjmp's caller, we |
135 | need to unwind shadow stack by one more frame. */ |
136 | addq $1, %rax |
137 | movl $255, %ebx |
138 | L(loop): |
139 | cmpq %rbx, %rax |
140 | cmovb %rax, %rbx |
141 | incsspq %rbx |
142 | subq %rbx, %rax |
143 | ja L(loop) |
144 | L(skip_ssp): |
145 | #endif |
146 | LIBC_PROBE (longjmp, 3, LP_SIZE@%RDI_LP, -4@%esi, LP_SIZE@%RDX_LP) |
147 | /* We add unwind information for the target here. */ |
148 | cfi_def_cfa(%rdi, 0) |
149 | cfi_register(%rsp,%r8) |
150 | cfi_register(%rbp,%r9) |
151 | cfi_register(%rip,%rdx) |
152 | cfi_offset(%rbx,JB_RBX*8) |
153 | cfi_offset(%r12,JB_R12*8) |
154 | cfi_offset(%r13,JB_R13*8) |
155 | cfi_offset(%r14,JB_R14*8) |
156 | cfi_offset(%r15,JB_R15*8) |
157 | movq (JB_RBX*8)(%rdi), %rbx |
158 | movq (JB_R12*8)(%rdi), %r12 |
159 | movq (JB_R13*8)(%rdi), %r13 |
160 | movq (JB_R14*8)(%rdi), %r14 |
161 | movq (JB_R15*8)(%rdi), %r15 |
162 | /* Set return value for setjmp. */ |
163 | movl %esi, %eax |
164 | mov %R8_LP, %RSP_LP |
165 | movq %r9,%rbp |
166 | LIBC_PROBE (longjmp_target, 3, |
167 | LP_SIZE@%RDI_LP, -4@%eax, LP_SIZE@%RDX_LP) |
168 | jmpq *%rdx |
169 | END (____longjmp_chk) |
170 | |