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