1/* Copyright (C) 2001-2022 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 <jmpbuf-offsets.h>
20#include <jmp_buf-ssp.h>
21#include <asm-syntax.h>
22#include <stap-probe.h>
23
24/* Don't restore shadow stack register if shadow stack isn't enabled.  */
25#if !SHSTK_ENABLED
26# undef SHADOW_STACK_POINTER_OFFSET
27#endif
28
29	.section .rodata.str1.1,"aMS",@progbits,1
30	.type	longjmp_msg,@object
31longjmp_msg:
32	.string "longjmp causes uninitialized stack frame"
33	.size	longjmp_msg, .-longjmp_msg
34
35
36#ifdef PIC
37# define CALL_FAIL	movl	%ebx, %ecx;				      \
38			cfi_register(%ebx,%ecx);			      \
39			LOAD_PIC_REG (bx);				      \
40			leal	longjmp_msg@GOTOFF(%ebx), %eax;		      \
41			movl	%eax, (%esp);				      \
42			call	HIDDEN_JUMPTARGET(__fortify_fail)
43#else
44# define CALL_FAIL	movl	$longjmp_msg, %eax;			      \
45			movl	%eax, (%esp);				      \
46			call	HIDDEN_JUMPTARGET(__fortify_fail)
47#endif
48
49
50	.text
51ENTRY (____longjmp_chk)
52	movl	4(%esp), %ecx	/* User's jmp_buf in %ecx.  */
53
54#ifdef SHADOW_STACK_POINTER_OFFSET
55# if IS_IN (libc) && defined SHARED && defined FEATURE_1_OFFSET
56	/* Check if Shadow Stack is enabled.  */
57	testl	$X86_FEATURE_1_SHSTK, %gs:FEATURE_1_OFFSET
58	jz	L(skip_ssp)
59# else
60	xorl	%edx, %edx
61# endif
62	/* Check and adjust the Shadow-Stack-Pointer.  */
63	rdsspd	%edx
64	/* And compare it with the saved ssp value.  */
65	subl	SHADOW_STACK_POINTER_OFFSET(%ecx), %edx
66	je	L(skip_ssp)
67	/* Count the number of frames to adjust and adjust it
68	   with incssp instruction.  The instruction can adjust
69	   the ssp by [0..255] value only thus use a loop if
70	   the number of frames is bigger than 255.  */
71	negl	%edx
72	shrl	$2, %edx
73	/* NB: We saved Shadow-Stack-Pointer of setjmp.  Since we are
74	       restoring Shadow-Stack-Pointer of setjmp's caller, we
75	       need to unwind shadow stack by one more frame.  */
76	addl	$1, %edx
77	movl	$255, %ebx
78L(loop):
79	cmpl	%ebx, %edx
80	cmovb	%edx, %ebx
81	incsspd	%ebx
82	subl	%ebx, %edx
83	ja	L(loop)
84L(skip_ssp):
85#endif
86	/* Save the return address now.  */
87	movl	(JB_PC*4)(%ecx), %edx
88	/* Get the stack pointer.  */
89	movl	(JB_SP*4)(%ecx), %edi
90	cfi_undefined(%edi)
91	PTR_DEMANGLE (%edx)
92	PTR_DEMANGLE (%edi)
93
94	cmpl	%edi, %esp
95	jbe	.Lok
96
97	subl	$12, %esp
98	cfi_adjust_cfa_offset(12)
99	xorl	%ebx, %ebx
100	movl	%esp, %ecx
101	movl	$__NR_sigaltstack, %eax
102	ENTER_KERNEL
103	/* Without working sigaltstack we cannot perform the test.  */
104	test	%eax, %eax
105	jne	.Lok2
106	testl	$1, 4(%esp)
107	jz	.Lfail
108
109	movl	(%esp), %eax
110	addl	8(%esp), %eax
111	subl	%edi, %eax
112	cmpl	8(%esp), %eax
113	jae	.Lok2
114
115.Lfail:	CALL_FAIL
116
117.Lok2:	addl	$12, %esp
118	cfi_adjust_cfa_offset(-12)
119	movl	4(%esp), %ecx
120
121.Lok:
122	LIBC_PROBE (longjmp, 3, 4@%ecx, -4@8(%esp), 4@%edx)
123	/* We add unwind information for the target here.  */
124	cfi_def_cfa(%ecx, 0)
125	cfi_register(%eip, %edx)
126	cfi_register(%esp, %edi)
127	cfi_offset(%ebx, JB_BX*4)
128	cfi_offset(%esi, JB_SI*4)
129	cfi_offset(%edi, JB_DI*4)
130	cfi_offset(%ebp, JB_BP*4)
131
132	movl	8(%esp), %eax	/* Second argument is return value.  */
133	movl	%edi, %esp
134
135	/* Restore registers.  */
136	movl	(JB_BX*4)(%ecx), %ebx
137	movl	(JB_SI*4)(%ecx), %esi
138	movl	(JB_DI*4)(%ecx), %edi
139	movl	(JB_BP*4)(%ecx), %ebp
140	cfi_restore(%ebx)
141	cfi_restore(%esi)
142	cfi_restore(%edi)
143	cfi_restore(%ebp)
144
145	/* Jump to saved PC.  */
146	LIBC_PROBE (longjmp_target, 3, 4@%ecx, -4@%eax, 4@%edx)
147	jmp	*%edx
148END (____longjmp_chk)
149