1/* Checked longjmp support. x86_64 Hurd version.
2 Copyright (C) 2001-2024 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 <pointer_guard.h>
21#include <jmpbuf-offsets.h>
22#include <asm-syntax.h>
23#include <tcb-offsets.h>
24#include <jmp_buf-ssp.h>
25#include <signal-defines.h>
26
27#define SS_ONSTACK 1
28
29/* Don't restore shadow stack register if shadow stack isn't enabled. */
30#if !SHSTK_ENABLED
31# undef SHADOW_STACK_POINTER_OFFSET
32#endif
33
34 .section .rodata.str1.1,"aMS",@progbits,1
35 .type longjmp_msg,@object
36longjmp_msg:
37 .string "longjmp causes uninitialized stack frame"
38 .size longjmp_msg, .-longjmp_msg
39
40
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
49/* Jump to the position specified by ENV, causing the
50 setjmp call there to return VAL, or 1 if VAL is 0.
51 void __longjmp (__jmp_buf env, int val). */
52 .text
53ENTRY(____longjmp_chk)
54 /* Restore registers. */
55 mov (JB_RSP*8)(%rdi), %R8_LP
56 mov (JB_RBP*8)(%rdi),%R9_LP
57 mov (JB_PC*8)(%rdi), %RDX_LP
58#ifdef PTR_DEMANGLE
59 PTR_DEMANGLE (%R8_LP)
60 PTR_DEMANGLE (%R9_LP)
61 PTR_DEMANGLE (%RDX_LP)
62#endif
63
64#if !defined (SHARED) || IS_IN (rtld)
65 cmpb $0, __libc_tls_initialized(%rip)
66 jz .Lok /* TLS not initialized yet */
67#endif
68
69 movq %fs:SIGSTATE_OFFSET, %R10_LP
70 testq %R10_LP, %R10_LP
71 jz .Lok /* sigstate not initialized yet */
72
73 testl $SS_ONSTACK, (HURD_SIGSTATE__SIGALTSTACK__OFFSET + SIGALTSTACK__SS_FLAGS__OFFSET)(%R10_LP)
74 jnz .Lonstack
75
76 /* We were on the main stack. Jumping to a higher-address
77 frame is always allowed, otherwise it's not allowed. */
78 cmp %R8_LP, %RSP_LP
79 jbe .Lok
80
81.Lfail: CALL_FAIL
82
83.Lonstack:
84 /* We were on the alternate stack, can't really easily check anything
85 since longjmp may get us out of the alternate stack. */
86
87 cmpq (HURD_SIGSTATE__SIGALTSTACK__OFFSET + SIGALTSTACK__SS_SP__OFFSET)(%R10_LP), %R8_LP
88 jb .Loks /* Jumping below the altstack, switch */
89
90 movq (HURD_SIGSTATE__SIGALTSTACK__OFFSET + SIGALTSTACK__SS_SP__OFFSET)(%R10_LP), %R11_LP
91 addq (HURD_SIGSTATE__SIGALTSTACK__OFFSET + SIGALTSTACK__SS_SIZE__OFFSET)(%R10_LP), %R11_LP
92 cmpq %R11_LP, %R8_LP
93 jb .Lok /* Jumping inside the altstack, do not switch */
94
95 /* Jumping above the altstack, switch */
96
97.Loks: /* We jump out of the alternate stack, clear SS_ONSTACK flag. */
98 andl $~(SS_ONSTACK), (HURD_SIGSTATE__SIGALTSTACK__OFFSET + SIGALTSTACK__SS_FLAGS__OFFSET)(%R10_LP)
99
100.Lok:
101 /* We add unwind information for the target here. */
102 cfi_def_cfa(%rdi, 0)
103 cfi_register(%rsp,%r8)
104 cfi_register(%rbp,%r9)
105 cfi_register(%rip,%rdx)
106 cfi_offset(%rbx,JB_RBX*8)
107 cfi_offset(%r12,JB_R12*8)
108 cfi_offset(%r13,JB_R13*8)
109 cfi_offset(%r14,JB_R14*8)
110 cfi_offset(%r15,JB_R15*8)
111 movq (JB_RBX*8)(%rdi), %rbx
112 movq (JB_R12*8)(%rdi), %r12
113 movq (JB_R13*8)(%rdi), %r13
114 movq (JB_R14*8)(%rdi), %r14
115 movq (JB_R15*8)(%rdi), %r15
116 /* Set return value for setjmp. */
117 movl %esi, %eax
118 mov %R8_LP, %RSP_LP
119 movq %r9,%rbp
120 jmpq *%rdx
121END (____longjmp_chk)
122

source code of glibc/sysdeps/mach/hurd/x86_64/____longjmp_chk.S