Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/tools/testing/selftests/arm64/gcs/gcs-locking.c
26292 views
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
202