| 1 | /* Linux/x86-64 CET initializers function. |
| 2 | Copyright (C) 2023-2024 Free Software Foundation, Inc. |
| 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 <sys/prctl.h> |
| 19 | #include <asm/prctl.h> |
| 20 | #include <features-offsets.h> |
| 21 | |
| 22 | static __always_inline int |
| 23 | dl_cet_disable_cet (unsigned int cet_feature) |
| 24 | { |
| 25 | if (cet_feature != GNU_PROPERTY_X86_FEATURE_1_SHSTK) |
| 26 | return -1; |
| 27 | long long int kernel_feature = ARCH_SHSTK_SHSTK; |
| 28 | return (int) INTERNAL_SYSCALL_CALL (arch_prctl, ARCH_SHSTK_DISABLE, |
| 29 | kernel_feature); |
| 30 | } |
| 31 | |
| 32 | static __always_inline int |
| 33 | dl_cet_lock_cet (unsigned int cet_feature) |
| 34 | { |
| 35 | if (cet_feature != GNU_PROPERTY_X86_FEATURE_1_SHSTK) |
| 36 | return -1; |
| 37 | /* Lock all SHSTK features. */ |
| 38 | long long int kernel_feature = -1; |
| 39 | return (int) INTERNAL_SYSCALL_CALL (arch_prctl, ARCH_SHSTK_LOCK, |
| 40 | kernel_feature); |
| 41 | } |
| 42 | |
| 43 | static __always_inline unsigned int |
| 44 | dl_cet_get_cet_status (void) |
| 45 | { |
| 46 | unsigned long long kernel_feature; |
| 47 | unsigned int status = 0; |
| 48 | if (INTERNAL_SYSCALL_CALL (arch_prctl, ARCH_SHSTK_STATUS, |
| 49 | &kernel_feature) == 0) |
| 50 | { |
| 51 | if ((kernel_feature & ARCH_SHSTK_SHSTK) != 0) |
| 52 | status = GNU_PROPERTY_X86_FEATURE_1_SHSTK; |
| 53 | } |
| 54 | return status; |
| 55 | } |
| 56 | |
| 57 | static __always_inline bool |
| 58 | dl_cet_ibt_enabled (void) |
| 59 | { |
| 60 | unsigned int feature_1 = THREAD_GETMEM (THREAD_SELF, |
| 61 | header.feature_1); |
| 62 | return (feature_1 & GNU_PROPERTY_X86_FEATURE_1_IBT) != 0; |
| 63 | } |
| 64 | |
| 65 | /* Enable shadow stack with a macro to avoid shadow stack underflow. */ |
| 66 | #define ENABLE_X86_CET(cet_feature) \ |
| 67 | if ((cet_feature & GNU_PROPERTY_X86_FEATURE_1_SHSTK)) \ |
| 68 | { \ |
| 69 | long long int kernel_feature = ARCH_SHSTK_SHSTK; \ |
| 70 | INTERNAL_SYSCALL_CALL (arch_prctl, ARCH_SHSTK_ENABLE, \ |
| 71 | kernel_feature); \ |
| 72 | } |
| 73 | |
| 74 | #define X86_STRINGIFY_1(x) #x |
| 75 | #define X86_STRINGIFY(x) X86_STRINGIFY_1 (x) |
| 76 | |
| 77 | /* Enable shadow stack before calling _dl_init if it is enabled in |
| 78 | GL(dl_x86_feature_1). Call _dl_setup_x86_features to setup shadow |
| 79 | stack. */ |
| 80 | #define RTLD_START_ENABLE_X86_FEATURES \ |
| 81 | "\ |
| 82 | # Check if shadow stack is enabled in GL(dl_x86_feature_1).\n\ |
| 83 | movl _rtld_local+" X86_STRINGIFY (RTLD_GLOBAL_DL_X86_FEATURE_1_OFFSET) "(%rip), %edx\n\ |
| 84 | testl $" X86_STRINGIFY (X86_FEATURE_1_SHSTK) ", %edx\n\ |
| 85 | jz 1f\n\ |
| 86 | # Enable shadow stack if enabled in GL(dl_x86_feature_1).\n\ |
| 87 | movl $" X86_STRINGIFY (ARCH_SHSTK_SHSTK) ", %esi\n\ |
| 88 | movl $" X86_STRINGIFY (ARCH_SHSTK_ENABLE) ", %edi\n\ |
| 89 | movl $" X86_STRINGIFY (__NR_arch_prctl) ", %eax\n\ |
| 90 | syscall\n\ |
| 91 | 1:\n\ |
| 92 | # Pass GL(dl_x86_feature_1) to _dl_cet_setup_features.\n\ |
| 93 | movl %edx, %edi\n\ |
| 94 | # Align stack for the _dl_cet_setup_features call.\n\ |
| 95 | and $-16, %" RSP_LP "\n\ |
| 96 | call _dl_cet_setup_features\n\ |
| 97 | # Restore %rax and %rsp from %r12 and %r13.\n\ |
| 98 | mov %" R12_LP ", %" RAX_LP "\n\ |
| 99 | mov %" R13_LP ", %" RSP_LP "\n\ |
| 100 | " |
| 101 | |