1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (C) 2023 ARM Limited. 4 * 5 * Tests for GCS mode locking. These tests rely on both having GCS 6 * unconfigured on entry and on the kselftest harness running each 7 * test in a fork()ed process which will have it's own mode. 8 */ 9 10 #include <limits.h> 11 12 #include <sys/auxv.h> 13 #include <sys/prctl.h> 14 15 #include <asm/hwcap.h> 16 17 #include "kselftest_harness.h" 18 19 #include "gcs-util.h" 20 21 #define my_syscall2(num, arg1, arg2) \ 22 ({ \ 23 register long _num __asm__ ("x8") = (num); \ 24 register long _arg1 __asm__ ("x0") = (long)(arg1); \ 25 register long _arg2 __asm__ ("x1") = (long)(arg2); \ 26 register long _arg3 __asm__ ("x2") = 0; \ 27 register long _arg4 __asm__ ("x3") = 0; \ 28 register long _arg5 __asm__ ("x4") = 0; \ 29 \ 30 __asm__ volatile ( \ 31 "svc #0\n" \ 32 : "=r"(_arg1) \ 33 : "r"(_arg1), "r"(_arg2), \ 34 "r"(_arg3), "r"(_arg4), \ 35 "r"(_arg5), "r"(_num) \ 36 : "memory", "cc" \ 37 ); \ 38 _arg1; \ 39 }) 40 41 /* No mode bits are rejected for locking */ 42 TEST(lock_all_modes) 43 { 44 int ret; 45 46 ret = prctl(PR_LOCK_SHADOW_STACK_STATUS, ULONG_MAX, 0, 0, 0); 47 ASSERT_EQ(ret, 0); 48 } 49 50 FIXTURE(valid_modes) 51 { 52 }; 53 54 FIXTURE_VARIANT(valid_modes) 55 { 56 unsigned long mode; 57 }; 58 59 FIXTURE_VARIANT_ADD(valid_modes, enable) 60 { 61 .mode = PR_SHADOW_STACK_ENABLE, 62 }; 63 64 FIXTURE_VARIANT_ADD(valid_modes, enable_write) 65 { 66 .mode = PR_SHADOW_STACK_ENABLE | PR_SHADOW_STACK_WRITE, 67 }; 68 69 FIXTURE_VARIANT_ADD(valid_modes, enable_push) 70 { 71 .mode = PR_SHADOW_STACK_ENABLE | PR_SHADOW_STACK_PUSH, 72 }; 73 74 FIXTURE_VARIANT_ADD(valid_modes, enable_write_push) 75 { 76 .mode = PR_SHADOW_STACK_ENABLE | PR_SHADOW_STACK_WRITE | 77 PR_SHADOW_STACK_PUSH, 78 }; 79 80 FIXTURE_VARIANT_ADD(valid_modes, write) 81 { 82 .mode = PR_SHADOW_STACK_WRITE, 83 }; 84 85 FIXTURE_VARIANT_ADD(valid_modes, push) 86 { 87 .mode = PR_SHADOW_STACK_PUSH, 88 }; 89 90 FIXTURE_VARIANT_ADD(valid_modes, write_push) 91 { 92 .mode = PR_SHADOW_STACK_WRITE | PR_SHADOW_STACK_PUSH, 93 }; 94 95 FIXTURE_SETUP(valid_modes) 96 { 97 } 98 99 FIXTURE_TEARDOWN(valid_modes) 100 { 101 } 102 103 /* We can set the mode at all */ 104 TEST_F(valid_modes, set) 105 { 106 int ret; 107 108 ret = my_syscall2(__NR_prctl, PR_SET_SHADOW_STACK_STATUS, 109 variant->mode); 110 ASSERT_EQ(ret, 0); 111 112 _exit(0); 113 } 114 115 /* Enabling, locking then disabling is rejected */ 116 TEST_F(valid_modes, enable_lock_disable) 117 { 118 unsigned long mode; 119 int ret; 120 121 ret = my_syscall2(__NR_prctl, PR_SET_SHADOW_STACK_STATUS, 122 variant->mode); 123 ASSERT_EQ(ret, 0); 124 125 ret = prctl(PR_GET_SHADOW_STACK_STATUS, &mode, 0, 0, 0); 126 ASSERT_EQ(ret, 0); 127 ASSERT_EQ(mode, variant->mode); 128 129 ret = prctl(PR_LOCK_SHADOW_STACK_STATUS, variant->mode, 0, 0, 0); 130 ASSERT_EQ(ret, 0); 131 132 ret = my_syscall2(__NR_prctl, PR_SET_SHADOW_STACK_STATUS, 0); 133 ASSERT_EQ(ret, -EPERM); 134 135 _exit(0); 136 } 137 138 /* Locking then enabling is rejected */ 139 TEST_F(valid_modes, lock_enable) 140 { 141 unsigned long mode; 142 int ret; 143 144 ret = prctl(PR_LOCK_SHADOW_STACK_STATUS, variant->mode, 0, 0, 0); 145 ASSERT_EQ(ret, 0); 146 147 ret = my_syscall2(__NR_prctl, PR_SET_SHADOW_STACK_STATUS, 148 variant->mode); 149 ASSERT_EQ(ret, -EPERM); 150 151 ret = prctl(PR_GET_SHADOW_STACK_STATUS, &mode, 0, 0, 0); 152 ASSERT_EQ(ret, 0); 153 ASSERT_EQ(mode, 0); 154 155 _exit(0); 156 } 157 158 /* Locking then changing other modes is fine */ 159 TEST_F(valid_modes, lock_enable_disable_others) 160 { 161 unsigned long mode; 162 int ret; 163 164 ret = my_syscall2(__NR_prctl, PR_SET_SHADOW_STACK_STATUS, 165 variant->mode); 166 ASSERT_EQ(ret, 0); 167 168 ret = prctl(PR_GET_SHADOW_STACK_STATUS, &mode, 0, 0, 0); 169 ASSERT_EQ(ret, 0); 170 ASSERT_EQ(mode, variant->mode); 171 172 ret = prctl(PR_LOCK_SHADOW_STACK_STATUS, variant->mode, 0, 0, 0); 173 ASSERT_EQ(ret, 0); 174 175 ret = my_syscall2(__NR_prctl, PR_SET_SHADOW_STACK_STATUS, 176 PR_SHADOW_STACK_ALL_MODES); 177 ASSERT_EQ(ret, 0); 178 179 ret = prctl(PR_GET_SHADOW_STACK_STATUS, &mode, 0, 0, 0); 180 ASSERT_EQ(ret, 0); 181 ASSERT_EQ(mode, PR_SHADOW_STACK_ALL_MODES); 182 183 ret = my_syscall2(__NR_prctl, PR_SET_SHADOW_STACK_STATUS, 184 variant->mode); 185 ASSERT_EQ(ret, 0); 186 187 ret = prctl(PR_GET_SHADOW_STACK_STATUS, &mode, 0, 0, 0); 188 ASSERT_EQ(ret, 0); 189 ASSERT_EQ(mode, variant->mode); 190 191 _exit(0); 192 } 193 194 int main(int argc, char **argv) 195 { 196 unsigned long mode; 197 int ret; 198 199 if (!(getauxval(AT_HWCAP) & HWCAP_GCS)) 200 ksft_exit_skip("SKIP GCS not supported\n"); 201 202 ret = prctl(PR_GET_SHADOW_STACK_STATUS, &mode, 0, 0, 0); 203 if (ret) { 204 ksft_print_msg("Failed to read GCS state: %d\n", ret); 205 return EXIT_FAILURE; 206 } 207 208 if (mode & PR_SHADOW_STACK_ENABLE) { 209 ksft_print_msg("GCS was enabled, test unsupported\n"); 210 return KSFT_SKIP; 211 } 212 213 return test_harness_run(argc, argv); 214 } 215