| 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 <jmp_buf-ssp.h> | 
|---|
| 21 | #include <asm-syntax.h> | 
|---|
| 22 | #include <stap-probe.h> | 
|---|
| 23 |  | 
|---|
| 24 | /* Don't restore shadow stack register if | 
|---|
| 25 | 1. Shadow stack isn't enabled.  Or | 
|---|
| 26 | 2. __longjmp is defined for __longjmp_cancel. | 
|---|
| 27 | */ | 
|---|
| 28 | #if !SHSTK_ENABLED || defined __longjmp | 
|---|
| 29 | # undef SHADOW_STACK_POINTER_OFFSET | 
|---|
| 30 | #endif | 
|---|
| 31 |  | 
|---|
| 32 | /* Jump to the position specified by ENV, causing the | 
|---|
| 33 | setjmp call there to return VAL, or 1 if VAL is 0. | 
|---|
| 34 | void __longjmp (__jmp_buf env, int val).  */ | 
|---|
| 35 | .text | 
|---|
| 36 | ENTRY(__longjmp) | 
|---|
| 37 | /* Restore registers.  */ | 
|---|
| 38 | mov (JB_RSP*8)(%rdi),%R8_LP | 
|---|
| 39 | mov (JB_RBP*8)(%rdi),%R9_LP | 
|---|
| 40 | mov (JB_PC*8)(%rdi),%RDX_LP | 
|---|
| 41 | #ifdef PTR_DEMANGLE | 
|---|
| 42 | PTR_DEMANGLE (%R8_LP) | 
|---|
| 43 | PTR_DEMANGLE (%R9_LP) | 
|---|
| 44 | PTR_DEMANGLE (%RDX_LP) | 
|---|
| 45 | # ifdef __ILP32__ | 
|---|
| 46 | /* We ignored the high bits of the %rbp value because only the low | 
|---|
| 47 | bits are mangled.  But we cannot presume that %rbp is being used | 
|---|
| 48 | as a pointer and truncate it, so recover the high bits.  */ | 
|---|
| 49 | movl (JB_RBP*8 + 4)(%rdi), %eax | 
|---|
| 50 | shlq $32, %rax | 
|---|
| 51 | orq %rax, %r9 | 
|---|
| 52 | # endif | 
|---|
| 53 | #endif | 
|---|
| 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, %fs:FEATURE_1_OFFSET | 
|---|
| 58 | jz L(skip_ssp) | 
|---|
| 59 | # else | 
|---|
| 60 | xorl %eax, %eax | 
|---|
| 61 | # endif | 
|---|
| 62 | /* Check and adjust the Shadow-Stack-Pointer.  */ | 
|---|
| 63 | /* Get the current ssp.  */ | 
|---|
| 64 | rdsspq %rax | 
|---|
| 65 | /* And compare it with the saved ssp value.  */ | 
|---|
| 66 | subq SHADOW_STACK_POINTER_OFFSET(%rdi), %rax | 
|---|
| 67 | je L(skip_ssp) | 
|---|
| 68 | /* Count the number of frames to adjust and adjust it | 
|---|
| 69 | with incssp instruction.  The instruction can adjust | 
|---|
| 70 | the ssp by [0..255] value only thus use a loop if | 
|---|
| 71 | the number of frames is bigger than 255.  */ | 
|---|
| 72 | negq %rax | 
|---|
| 73 | shrq $3, %rax | 
|---|
| 74 | /* NB: We saved Shadow-Stack-Pointer of setjmp.  Since we are | 
|---|
| 75 | restoring Shadow-Stack-Pointer of setjmp's caller, we | 
|---|
| 76 | need to unwind shadow stack by one more frame.  */ | 
|---|
| 77 | addq $1, %rax | 
|---|
| 78 |  | 
|---|
| 79 | movl $255, %ebx | 
|---|
| 80 | L(loop): | 
|---|
| 81 | cmpq %rbx, %rax | 
|---|
| 82 | cmovb %rax, %rbx | 
|---|
| 83 | incsspq %rbx | 
|---|
| 84 | subq %rbx, %rax | 
|---|
| 85 | ja L(loop) | 
|---|
| 86 |  | 
|---|
| 87 | L(skip_ssp): | 
|---|
| 88 | #endif | 
|---|
| 89 | LIBC_PROBE (longjmp, 3, LP_SIZE@%RDI_LP, -4@%esi, LP_SIZE@%RDX_LP) | 
|---|
| 90 | /* We add unwind information for the target here.  */ | 
|---|
| 91 | cfi_def_cfa(%rdi, 0) | 
|---|
| 92 | cfi_register(%rsp,%r8) | 
|---|
| 93 | cfi_register(%rbp,%r9) | 
|---|
| 94 | cfi_register(%rip,%rdx) | 
|---|
| 95 | cfi_offset(%rbx,JB_RBX*8) | 
|---|
| 96 | cfi_offset(%r12,JB_R12*8) | 
|---|
| 97 | cfi_offset(%r13,JB_R13*8) | 
|---|
| 98 | cfi_offset(%r14,JB_R14*8) | 
|---|
| 99 | cfi_offset(%r15,JB_R15*8) | 
|---|
| 100 | movq (JB_RBX*8)(%rdi),%rbx | 
|---|
| 101 | movq (JB_R12*8)(%rdi),%r12 | 
|---|
| 102 | movq (JB_R13*8)(%rdi),%r13 | 
|---|
| 103 | movq (JB_R14*8)(%rdi),%r14 | 
|---|
| 104 | movq (JB_R15*8)(%rdi),%r15 | 
|---|
| 105 | /* Set return value for setjmp.  */ | 
|---|
| 106 | mov %esi, %eax | 
|---|
| 107 | mov %R8_LP,%RSP_LP | 
|---|
| 108 | movq %r9,%rbp | 
|---|
| 109 | LIBC_PROBE (longjmp_target, 3, | 
|---|
| 110 | LP_SIZE@%RDI_LP, -4@%eax, LP_SIZE@%RDX_LP) | 
|---|
| 111 | jmpq *%rdx | 
|---|
| 112 | END (__longjmp) | 
|---|
| 113 |  | 
|---|