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_SETUP(valid_modes) 81 { 82 } 83 84 FIXTURE_TEARDOWN(valid_modes) 85 { 86 } 87 88 /* We can set the mode at all */ 89 TEST_F(valid_modes, set) 90 { 91 int ret; 92 93 ret = my_syscall2(__NR_prctl, PR_SET_SHADOW_STACK_STATUS, 94 variant->mode); 95 ASSERT_EQ(ret, 0); 96 97 _exit(0); 98 } 99 100 /* Enabling, locking then disabling is rejected */ 101 TEST_F(valid_modes, enable_lock_disable) 102 { 103 unsigned long mode; 104 int ret; 105 106 ret = my_syscall2(__NR_prctl, PR_SET_SHADOW_STACK_STATUS, 107 variant->mode); 108 ASSERT_EQ(ret, 0); 109 110 ret = prctl(PR_GET_SHADOW_STACK_STATUS, &mode, 0, 0, 0); 111 ASSERT_EQ(ret, 0); 112 ASSERT_EQ(mode, variant->mode); 113 114 ret = prctl(PR_LOCK_SHADOW_STACK_STATUS, variant->mode, 0, 0, 0); 115 ASSERT_EQ(ret, 0); 116 117 ret = my_syscall2(__NR_prctl, PR_SET_SHADOW_STACK_STATUS, 0); 118 ASSERT_EQ(ret, -EBUSY); 119 120 _exit(0); 121 } 122 123 /* Locking then enabling is rejected */ 124 TEST_F(valid_modes, lock_enable) 125 { 126 unsigned long mode; 127 int ret; 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, 133 variant->mode); 134 ASSERT_EQ(ret, -EBUSY); 135 136 ret = prctl(PR_GET_SHADOW_STACK_STATUS, &mode, 0, 0, 0); 137 ASSERT_EQ(ret, 0); 138 ASSERT_EQ(mode, 0); 139 140 _exit(0); 141 } 142 143 /* Locking then changing other modes is fine */ 144 TEST_F(valid_modes, lock_enable_disable_others) 145 { 146 unsigned long mode; 147 int ret; 148 149 ret = my_syscall2(__NR_prctl, PR_SET_SHADOW_STACK_STATUS, 150 variant->mode); 151 ASSERT_EQ(ret, 0); 152 153 ret = prctl(PR_GET_SHADOW_STACK_STATUS, &mode, 0, 0, 0); 154 ASSERT_EQ(ret, 0); 155 ASSERT_EQ(mode, variant->mode); 156 157 ret = prctl(PR_LOCK_SHADOW_STACK_STATUS, variant->mode, 0, 0, 0); 158 ASSERT_EQ(ret, 0); 159 160 ret = my_syscall2(__NR_prctl, PR_SET_SHADOW_STACK_STATUS, 161 PR_SHADOW_STACK_ALL_MODES); 162 ASSERT_EQ(ret, 0); 163 164 ret = prctl(PR_GET_SHADOW_STACK_STATUS, &mode, 0, 0, 0); 165 ASSERT_EQ(ret, 0); 166 ASSERT_EQ(mode, PR_SHADOW_STACK_ALL_MODES); 167 168 169 ret = my_syscall2(__NR_prctl, PR_SET_SHADOW_STACK_STATUS, 170 variant->mode); 171 ASSERT_EQ(ret, 0); 172 173 ret = prctl(PR_GET_SHADOW_STACK_STATUS, &mode, 0, 0, 0); 174 ASSERT_EQ(ret, 0); 175 ASSERT_EQ(mode, variant->mode); 176 177 _exit(0); 178 } 179 180 int main(int argc, char **argv) 181 { 182 unsigned long mode; 183 int ret; 184 185 if (!(getauxval(AT_HWCAP) & HWCAP_GCS)) 186 ksft_exit_skip("SKIP GCS not supported\n"); 187 188 ret = prctl(PR_GET_SHADOW_STACK_STATUS, &mode, 0, 0, 0); 189 if (ret) { 190 ksft_print_msg("Failed to read GCS state: %d\n", ret); 191 return EXIT_FAILURE; 192 } 193 194 if (mode & PR_SHADOW_STACK_ENABLE) { 195 ksft_print_msg("GCS was enabled, test unsupported\n"); 196 return KSFT_SKIP; 197 } 198 199 return test_harness_run(argc, argv); 200 } 201