1 // SPDX-License-Identifier: GPL-2.0-only
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.
13 #include <sys/prctl.h>
15 #include <asm/hwcap.h>
17 #include "kselftest_harness.h"
21 #define my_syscall2(num, arg1, arg2) \
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; \
33 : "r"(_arg1), "r"(_arg2), \
34 "r"(_arg3), "r"(_arg4), \
35 "r"(_arg5), "r"(_num) \
41 /* No mode bits are rejected for locking */
46 ret
= prctl(PR_LOCK_SHADOW_STACK_STATUS
, ULONG_MAX
, 0, 0, 0);
54 FIXTURE_VARIANT(valid_modes
)
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
|
80 FIXTURE_SETUP(valid_modes
)
84 FIXTURE_TEARDOWN(valid_modes
)
88 /* We can set the mode at all */
89 TEST_F(valid_modes
, set
)
93 ret
= my_syscall2(__NR_prctl
, PR_SET_SHADOW_STACK_STATUS
,
100 /* Enabling, locking then disabling is rejected */
101 TEST_F(valid_modes
, enable_lock_disable
)
106 ret
= my_syscall2(__NR_prctl
, PR_SET_SHADOW_STACK_STATUS
,
110 ret
= prctl(PR_GET_SHADOW_STACK_STATUS
, &mode
, 0, 0, 0);
112 ASSERT_EQ(mode
, variant
->mode
);
114 ret
= prctl(PR_LOCK_SHADOW_STACK_STATUS
, variant
->mode
, 0, 0, 0);
117 ret
= my_syscall2(__NR_prctl
, PR_SET_SHADOW_STACK_STATUS
, 0);
118 ASSERT_EQ(ret
, -EBUSY
);
123 /* Locking then enabling is rejected */
124 TEST_F(valid_modes
, lock_enable
)
129 ret
= prctl(PR_LOCK_SHADOW_STACK_STATUS
, variant
->mode
, 0, 0, 0);
132 ret
= my_syscall2(__NR_prctl
, PR_SET_SHADOW_STACK_STATUS
,
134 ASSERT_EQ(ret
, -EBUSY
);
136 ret
= prctl(PR_GET_SHADOW_STACK_STATUS
, &mode
, 0, 0, 0);
143 /* Locking then changing other modes is fine */
144 TEST_F(valid_modes
, lock_enable_disable_others
)
149 ret
= my_syscall2(__NR_prctl
, PR_SET_SHADOW_STACK_STATUS
,
153 ret
= prctl(PR_GET_SHADOW_STACK_STATUS
, &mode
, 0, 0, 0);
155 ASSERT_EQ(mode
, variant
->mode
);
157 ret
= prctl(PR_LOCK_SHADOW_STACK_STATUS
, variant
->mode
, 0, 0, 0);
160 ret
= my_syscall2(__NR_prctl
, PR_SET_SHADOW_STACK_STATUS
,
161 PR_SHADOW_STACK_ALL_MODES
);
164 ret
= prctl(PR_GET_SHADOW_STACK_STATUS
, &mode
, 0, 0, 0);
166 ASSERT_EQ(mode
, PR_SHADOW_STACK_ALL_MODES
);
169 ret
= my_syscall2(__NR_prctl
, PR_SET_SHADOW_STACK_STATUS
,
173 ret
= prctl(PR_GET_SHADOW_STACK_STATUS
, &mode
, 0, 0, 0);
175 ASSERT_EQ(mode
, variant
->mode
);
180 int main(int argc
, char **argv
)
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);
190 ksft_print_msg("Failed to read GCS state: %d\n", ret
);
194 if (mode
& PR_SHADOW_STACK_ENABLE
) {
195 ksft_print_msg("GCS was enabled, test unsupported\n");
199 return test_harness_run(argc
, argv
);