Merge tag 'trace-printf-v6.13' of git://git.kernel.org/pub/scm/linux/kernel/git/trace...
[drm/drm-misc.git] / tools / testing / selftests / arm64 / gcs / gcs-locking.c
blob989f75a491b757b9da55fc4a22c28bcc4475eb03
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * Copyright (C) 2023 ARM Limited.
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 */
10 #include <limits.h>
12 #include <sys/auxv.h>
13 #include <sys/prctl.h>
15 #include <asm/hwcap.h>
17 #include "kselftest_harness.h"
19 #include "gcs-util.h"
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; \
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; \
41 /* No mode bits are rejected for locking */
42 TEST(lock_all_modes)
44 int ret;
46 ret = prctl(PR_LOCK_SHADOW_STACK_STATUS, ULONG_MAX, 0, 0, 0);
47 ASSERT_EQ(ret, 0);
50 FIXTURE(valid_modes)
54 FIXTURE_VARIANT(valid_modes)
56 unsigned long mode;
59 FIXTURE_VARIANT_ADD(valid_modes, enable)
61 .mode = PR_SHADOW_STACK_ENABLE,
64 FIXTURE_VARIANT_ADD(valid_modes, enable_write)
66 .mode = PR_SHADOW_STACK_ENABLE | PR_SHADOW_STACK_WRITE,
69 FIXTURE_VARIANT_ADD(valid_modes, enable_push)
71 .mode = PR_SHADOW_STACK_ENABLE | PR_SHADOW_STACK_PUSH,
74 FIXTURE_VARIANT_ADD(valid_modes, enable_write_push)
76 .mode = PR_SHADOW_STACK_ENABLE | PR_SHADOW_STACK_WRITE |
77 PR_SHADOW_STACK_PUSH,
80 FIXTURE_SETUP(valid_modes)
84 FIXTURE_TEARDOWN(valid_modes)
88 /* We can set the mode at all */
89 TEST_F(valid_modes, set)
91 int ret;
93 ret = my_syscall2(__NR_prctl, PR_SET_SHADOW_STACK_STATUS,
94 variant->mode);
95 ASSERT_EQ(ret, 0);
97 _exit(0);
100 /* Enabling, locking then disabling is rejected */
101 TEST_F(valid_modes, enable_lock_disable)
103 unsigned long mode;
104 int ret;
106 ret = my_syscall2(__NR_prctl, PR_SET_SHADOW_STACK_STATUS,
107 variant->mode);
108 ASSERT_EQ(ret, 0);
110 ret = prctl(PR_GET_SHADOW_STACK_STATUS, &mode, 0, 0, 0);
111 ASSERT_EQ(ret, 0);
112 ASSERT_EQ(mode, variant->mode);
114 ret = prctl(PR_LOCK_SHADOW_STACK_STATUS, variant->mode, 0, 0, 0);
115 ASSERT_EQ(ret, 0);
117 ret = my_syscall2(__NR_prctl, PR_SET_SHADOW_STACK_STATUS, 0);
118 ASSERT_EQ(ret, -EBUSY);
120 _exit(0);
123 /* Locking then enabling is rejected */
124 TEST_F(valid_modes, lock_enable)
126 unsigned long mode;
127 int ret;
129 ret = prctl(PR_LOCK_SHADOW_STACK_STATUS, variant->mode, 0, 0, 0);
130 ASSERT_EQ(ret, 0);
132 ret = my_syscall2(__NR_prctl, PR_SET_SHADOW_STACK_STATUS,
133 variant->mode);
134 ASSERT_EQ(ret, -EBUSY);
136 ret = prctl(PR_GET_SHADOW_STACK_STATUS, &mode, 0, 0, 0);
137 ASSERT_EQ(ret, 0);
138 ASSERT_EQ(mode, 0);
140 _exit(0);
143 /* Locking then changing other modes is fine */
144 TEST_F(valid_modes, lock_enable_disable_others)
146 unsigned long mode;
147 int ret;
149 ret = my_syscall2(__NR_prctl, PR_SET_SHADOW_STACK_STATUS,
150 variant->mode);
151 ASSERT_EQ(ret, 0);
153 ret = prctl(PR_GET_SHADOW_STACK_STATUS, &mode, 0, 0, 0);
154 ASSERT_EQ(ret, 0);
155 ASSERT_EQ(mode, variant->mode);
157 ret = prctl(PR_LOCK_SHADOW_STACK_STATUS, variant->mode, 0, 0, 0);
158 ASSERT_EQ(ret, 0);
160 ret = my_syscall2(__NR_prctl, PR_SET_SHADOW_STACK_STATUS,
161 PR_SHADOW_STACK_ALL_MODES);
162 ASSERT_EQ(ret, 0);
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);
169 ret = my_syscall2(__NR_prctl, PR_SET_SHADOW_STACK_STATUS,
170 variant->mode);
171 ASSERT_EQ(ret, 0);
173 ret = prctl(PR_GET_SHADOW_STACK_STATUS, &mode, 0, 0, 0);
174 ASSERT_EQ(ret, 0);
175 ASSERT_EQ(mode, variant->mode);
177 _exit(0);
180 int main(int argc, char **argv)
182 unsigned long mode;
183 int ret;
185 if (!(getauxval(AT_HWCAP) & HWCAP_GCS))
186 ksft_exit_skip("SKIP GCS not supported\n");
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;
194 if (mode & PR_SHADOW_STACK_ENABLE) {
195 ksft_print_msg("GCS was enabled, test unsupported\n");
196 return KSFT_SKIP;
199 return test_harness_run(argc, argv);