FILE
gcs-locking.c
File preview with syntax highlighting.
linux-6.19.14/tools/testing/selftests/arm64/gcs/gcs-locking.c
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 */ 42TEST(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 50FIXTURE(valid_modes) 51{ 52}; 53 54FIXTURE_VARIANT(valid_modes) 55{ 56 unsigned long mode; 57}; 58 59FIXTURE_VARIANT_ADD(valid_modes, enable) 60{ 61 .mode = PR_SHADOW_STACK_ENABLE, 62}; 63 64FIXTURE_VARIANT_ADD(valid_modes, enable_write) 65{ 66 .mode = PR_SHADOW_STACK_ENABLE | PR_SHADOW_STACK_WRITE, 67}; 68 69FIXTURE_VARIANT_ADD(valid_modes, enable_push) 70{ 71 .mode = PR_SHADOW_STACK_ENABLE | PR_SHADOW_STACK_PUSH, 72}; 73 74FIXTURE_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 80FIXTURE_SETUP(valid_modes) 81{ 82} 83 84FIXTURE_TEARDOWN(valid_modes) 85{ 86} 87 88/* We can set the mode at all */ 89TEST_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 */ 101TEST_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 */ 124TEST_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 */ 144TEST_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 ret = my_syscall2(__NR_prctl, PR_SET_SHADOW_STACK_STATUS, 169 variant->mode); 170 ASSERT_EQ(ret, 0); 171 172 ret = prctl(PR_GET_SHADOW_STACK_STATUS, &mode, 0, 0, 0); 173 ASSERT_EQ(ret, 0); 174 ASSERT_EQ(mode, variant->mode); 175 176 _exit(0); 177} 178 179int main(int argc, char **argv) 180{ 181 unsigned long mode; 182 int ret; 183 184 if (!(getauxval(AT_HWCAP) & HWCAP_GCS)) 185 ksft_exit_skip("SKIP GCS not supported\n"); 186 187 ret = prctl(PR_GET_SHADOW_STACK_STATUS, &mode, 0, 0, 0); 188 if (ret) { 189 ksft_print_msg("Failed to read GCS state: %d\n", ret); 190 return EXIT_FAILURE; 191 } 192 193 if (mode & PR_SHADOW_STACK_ENABLE) { 194 ksft_print_msg("GCS was enabled, test unsupported\n"); 195 return KSFT_SKIP; 196 } 197 198 return test_harness_run(argc, argv); 199}
~/
Read-only file preview.