1 // SPDX-License-Identifier: GPL-2.0
2
3 #define _GNU_SOURCE
4
5 #include <elf.h>
6 #include <pthread.h>
7 #include <stdbool.h>
8
9 #include <asm/prctl.h>
10 #include <sys/ptrace.h>
11 #include <sys/syscall.h>
12 #include <sys/uio.h>
13 #include <sys/wait.h>
14
15 #include "helpers.h"
16 #include "xstate.h"
17
18 /*
19 * The userspace xstate test suite is designed to be generic and operates
20 * with randomized xstate data. However, some states require special handling:
21 *
22 * - PKRU and XTILECFG need specific adjustments, such as modifying
23 * randomization behavior or using fixed values.
24 * - But, PKRU already has a dedicated test suite in /tools/selftests/mm.
25 * - Legacy states (FP and SSE) are excluded, as they are not considered
26 * part of extended states (xstates) and their usage is already deeply
27 * integrated into user-space libraries.
28 */
29 #define XFEATURE_MASK_TEST_SUPPORTED \
30 ((1 << XFEATURE_YMM) | \
31 (1 << XFEATURE_OPMASK) | \
32 (1 << XFEATURE_ZMM_Hi256) | \
33 (1 << XFEATURE_Hi16_ZMM) | \
34 (1 << XFEATURE_XTILEDATA) | \
35 (1 << XFEATURE_APX))
36
37
38 static struct xstate_info xstate;
39
40 struct futex_info {
41 unsigned int iterations;
42 struct futex_info *next;
43 pthread_mutex_t mutex;
44 pthread_t thread;
45 bool valid;
46 int nr;
47 };
48
load_rand_xstate(struct xstate_info * xstate,struct xsave_buffer * xbuf)49 static inline void load_rand_xstate(struct xstate_info *xstate, struct xsave_buffer *xbuf)
50 {
51 clear_xstate_header(xbuf);
52 set_xstatebv(xbuf, xstate->mask);
53 set_rand_data(xstate, xbuf);
54 xrstor(xbuf, xstate->mask);
55 }
56
load_init_xstate(struct xstate_info * xstate,struct xsave_buffer * xbuf)57 static inline void load_init_xstate(struct xstate_info *xstate, struct xsave_buffer *xbuf)
58 {
59 clear_xstate_header(xbuf);
60 xrstor(xbuf, xstate->mask);
61 }
62
copy_xstate(struct xsave_buffer * xbuf_dst,struct xsave_buffer * xbuf_src)63 static inline void copy_xstate(struct xsave_buffer *xbuf_dst, struct xsave_buffer *xbuf_src)
64 {
65 memcpy(&xbuf_dst->bytes[xstate.xbuf_offset],
66 &xbuf_src->bytes[xstate.xbuf_offset],
67 xstate.size);
68 }
69
validate_xstate_same(struct xsave_buffer * xbuf1,struct xsave_buffer * xbuf2)70 static inline bool validate_xstate_same(struct xsave_buffer *xbuf1, struct xsave_buffer *xbuf2)
71 {
72 int ret;
73
74 ret = memcmp(&xbuf1->bytes[xstate.xbuf_offset],
75 &xbuf2->bytes[xstate.xbuf_offset],
76 xstate.size);
77 return ret == 0;
78 }
79
validate_xregs_same(struct xsave_buffer * xbuf1)80 static inline bool validate_xregs_same(struct xsave_buffer *xbuf1)
81 {
82 struct xsave_buffer *xbuf2;
83 bool ret;
84
85 xbuf2 = alloc_xbuf();
86 if (!xbuf2)
87 ksft_exit_fail_msg("failed to allocate XSAVE buffer\n");
88
89 xsave(xbuf2, xstate.mask);
90 ret = validate_xstate_same(xbuf1, xbuf2);
91
92 free(xbuf2);
93 return ret;
94 }
95
96 /* Context switching test */
97
check_xstate(void * info)98 static void *check_xstate(void *info)
99 {
100 struct futex_info *finfo = (struct futex_info *)info;
101 struct xsave_buffer *xbuf;
102 int i;
103
104 xbuf = alloc_xbuf();
105 if (!xbuf)
106 ksft_exit_fail_msg("unable to allocate XSAVE buffer\n");
107
108 /*
109 * Load random data into 'xbuf' and then restore it to the xstate
110 * registers.
111 */
112 load_rand_xstate(&xstate, xbuf);
113 finfo->valid = true;
114
115 for (i = 0; i < finfo->iterations; i++) {
116 pthread_mutex_lock(&finfo->mutex);
117
118 /*
119 * Ensure the register values have not diverged from the
120 * record. Then reload a new random value. If it failed
121 * ever before, skip it.
122 */
123 if (finfo->valid) {
124 finfo->valid = validate_xregs_same(xbuf);
125 load_rand_xstate(&xstate, xbuf);
126 }
127
128 /*
129 * The last thread's last unlock will be for thread 0's
130 * mutex. However, thread 0 will have already exited the
131 * loop and the mutex will already be unlocked.
132 *
133 * Because this is not an ERRORCHECK mutex, that
134 * inconsistency will be silently ignored.
135 */
136 pthread_mutex_unlock(&finfo->next->mutex);
137 }
138
139 free(xbuf);
140 return finfo;
141 }
142
create_threads(uint32_t num_threads,uint32_t iterations,struct futex_info * finfo)143 static void create_threads(uint32_t num_threads, uint32_t iterations, struct futex_info *finfo)
144 {
145 int i;
146
147 for (i = 0; i < num_threads; i++) {
148 int next_nr;
149
150 finfo[i].nr = i;
151 finfo[i].iterations = iterations;
152
153 /*
154 * Thread 'i' will wait on this mutex to be unlocked.
155 * Lock it immediately after initialization:
156 */
157 pthread_mutex_init(&finfo[i].mutex, NULL);
158 pthread_mutex_lock(&finfo[i].mutex);
159
160 next_nr = (i + 1) % num_threads;
161 finfo[i].next = &finfo[next_nr];
162
163 if (pthread_create(&finfo[i].thread, NULL, check_xstate, &finfo[i]))
164 ksft_exit_fail_msg("pthread_create() failed\n");
165 }
166 }
167
checkout_threads(uint32_t num_threads,struct futex_info * finfo)168 static bool checkout_threads(uint32_t num_threads, struct futex_info *finfo)
169 {
170 void *thread_retval;
171 bool valid = true;
172 int err, i;
173
174 for (i = 0; i < num_threads; i++) {
175 err = pthread_join(finfo[i].thread, &thread_retval);
176 if (err)
177 ksft_exit_fail_msg("pthread_join() failed for thread %d err: %d\n", i, err);
178
179 if (thread_retval != &finfo[i]) {
180 ksft_exit_fail_msg("unexpected thread retval for thread %d: %p\n",
181 i, thread_retval);
182 }
183
184 valid &= finfo[i].valid;
185 }
186
187 return valid;
188 }
189
affinitize_cpu0(void)190 static void affinitize_cpu0(void)
191 {
192 cpu_set_t cpuset;
193
194 CPU_ZERO(&cpuset);
195 CPU_SET(0, &cpuset);
196
197 if (sched_setaffinity(0, sizeof(cpuset), &cpuset) != 0)
198 ksft_exit_fail_msg("sched_setaffinity to CPU 0 failed\n");
199 }
200
test_context_switch(uint32_t num_threads,uint32_t iterations)201 static void test_context_switch(uint32_t num_threads, uint32_t iterations)
202 {
203 struct futex_info *finfo;
204
205 /* Affinitize to one CPU to force context switches */
206 affinitize_cpu0();
207
208 printf("[RUN]\t%s: check context switches, %d iterations, %d threads.\n",
209 xstate.name, iterations, num_threads);
210
211 finfo = malloc(sizeof(*finfo) * num_threads);
212 if (!finfo)
213 ksft_exit_fail_msg("unable allocate memory\n");
214
215 create_threads(num_threads, iterations, finfo);
216
217 /*
218 * This thread wakes up thread 0
219 * Thread 0 will wake up 1
220 * Thread 1 will wake up 2
221 * ...
222 * The last thread will wake up 0
223 *
224 * This will repeat for the configured
225 * number of iterations.
226 */
227 pthread_mutex_unlock(&finfo[0].mutex);
228
229 /* Wait for all the threads to finish: */
230 if (checkout_threads(num_threads, finfo))
231 printf("[OK]\tNo incorrect case was found.\n");
232 else
233 printf("[FAIL]\tFailed with context switching test.\n");
234
235 free(finfo);
236 }
237
238 /*
239 * Ptrace test for the ABI format as described in arch/x86/include/asm/user.h
240 */
241
242 /*
243 * Make sure the ptracee has the expanded kernel buffer on the first use.
244 * Then, initialize the state before performing the state injection from
245 * the ptracer. For non-dynamic states, this is benign.
246 */
ptracee_touch_xstate(void)247 static inline void ptracee_touch_xstate(void)
248 {
249 struct xsave_buffer *xbuf;
250
251 xbuf = alloc_xbuf();
252
253 load_rand_xstate(&xstate, xbuf);
254 load_init_xstate(&xstate, xbuf);
255
256 free(xbuf);
257 }
258
259 /*
260 * Ptracer injects the randomized xstate data. It also reads before and
261 * after that, which will execute the kernel's state copy functions.
262 */
ptracer_inject_xstate(pid_t target)263 static void ptracer_inject_xstate(pid_t target)
264 {
265 uint32_t xbuf_size = get_xbuf_size();
266 struct xsave_buffer *xbuf1, *xbuf2;
267 struct iovec iov;
268
269 /*
270 * Allocate buffers to keep data while ptracer can write the
271 * other buffer
272 */
273 xbuf1 = alloc_xbuf();
274 xbuf2 = alloc_xbuf();
275 if (!xbuf1 || !xbuf2)
276 ksft_exit_fail_msg("unable to allocate XSAVE buffer\n");
277
278 iov.iov_base = xbuf1;
279 iov.iov_len = xbuf_size;
280
281 if (ptrace(PTRACE_GETREGSET, target, (uint32_t)NT_X86_XSTATE, &iov))
282 ksft_exit_fail_msg("PTRACE_GETREGSET failed\n");
283
284 printf("[RUN]\t%s: inject xstate via ptrace().\n", xstate.name);
285
286 load_rand_xstate(&xstate, xbuf1);
287 copy_xstate(xbuf2, xbuf1);
288
289 if (ptrace(PTRACE_SETREGSET, target, (uint32_t)NT_X86_XSTATE, &iov))
290 ksft_exit_fail_msg("PTRACE_SETREGSET failed\n");
291
292 if (ptrace(PTRACE_GETREGSET, target, (uint32_t)NT_X86_XSTATE, &iov))
293 ksft_exit_fail_msg("PTRACE_GETREGSET failed\n");
294
295 if (*(uint64_t *)get_fpx_sw_bytes(xbuf1) == xgetbv(0))
296 printf("[OK]\t'xfeatures' in SW reserved area was correctly written\n");
297 else
298 printf("[FAIL]\t'xfeatures' in SW reserved area was not correctly written\n");
299
300 if (validate_xstate_same(xbuf2, xbuf1))
301 printf("[OK]\txstate was correctly updated.\n");
302 else
303 printf("[FAIL]\txstate was not correctly updated.\n");
304
305 free(xbuf1);
306 free(xbuf2);
307 }
308
test_ptrace(void)309 static void test_ptrace(void)
310 {
311 pid_t child;
312 int status;
313
314 child = fork();
315 if (child < 0) {
316 ksft_exit_fail_msg("fork() failed\n");
317 } else if (!child) {
318 if (ptrace(PTRACE_TRACEME, 0, NULL, NULL))
319 ksft_exit_fail_msg("PTRACE_TRACEME failed\n");
320
321 ptracee_touch_xstate();
322
323 raise(SIGTRAP);
324 _exit(0);
325 }
326
327 do {
328 wait(&status);
329 } while (WSTOPSIG(status) != SIGTRAP);
330
331 ptracer_inject_xstate(child);
332
333 ptrace(PTRACE_DETACH, child, NULL, NULL);
334 wait(&status);
335 if (!WIFEXITED(status) || WEXITSTATUS(status))
336 ksft_exit_fail_msg("ptracee exit error\n");
337 }
338
339 /*
340 * Test signal delivery for the ABI compatibility.
341 * See the ABI format: arch/x86/include/uapi/asm/sigcontext.h
342 */
343
344 /*
345 * Avoid using printf() in signal handlers as it is not
346 * async-signal-safe.
347 */
348 #define SIGNAL_BUF_LEN 1000
349 static char signal_message_buffer[SIGNAL_BUF_LEN];
sig_print(char * msg)350 static void sig_print(char *msg)
351 {
352 int left = SIGNAL_BUF_LEN - strlen(signal_message_buffer) - 1;
353
354 strncat(signal_message_buffer, msg, left);
355 }
356
357 static struct xsave_buffer *stashed_xbuf;
358
validate_sigfpstate(int sig,siginfo_t * si,void * ctx_void)359 static void validate_sigfpstate(int sig, siginfo_t *si, void *ctx_void)
360 {
361 ucontext_t *ctx = (ucontext_t *)ctx_void;
362 void *xbuf = ctx->uc_mcontext.fpregs;
363 struct _fpx_sw_bytes *sw_bytes;
364 uint32_t magic2;
365
366 /* Reset the signal message buffer: */
367 signal_message_buffer[0] = '\0';
368
369 sw_bytes = get_fpx_sw_bytes(xbuf);
370 if (sw_bytes->magic1 == FP_XSTATE_MAGIC1)
371 sig_print("[OK]\t'magic1' is valid\n");
372 else
373 sig_print("[FAIL]\t'magic1' is not valid\n");
374
375 if (get_fpx_sw_bytes_features(xbuf) & xstate.mask)
376 sig_print("[OK]\t'xfeatures' in SW reserved area is valid\n");
377 else
378 sig_print("[FAIL]\t'xfeatures' in SW reserved area is not valid\n");
379
380 if (get_xstatebv(xbuf) & xstate.mask)
381 sig_print("[OK]\t'xfeatures' in XSAVE header is valid\n");
382 else
383 sig_print("[FAIL]\t'xfeatures' in XSAVE header is not valid\n");
384
385 if (validate_xstate_same(stashed_xbuf, xbuf))
386 sig_print("[OK]\txstate delivery was successful\n");
387 else
388 sig_print("[FAIL]\txstate delivery was not successful\n");
389
390 magic2 = *(uint32_t *)(xbuf + sw_bytes->xstate_size);
391 if (magic2 == FP_XSTATE_MAGIC2)
392 sig_print("[OK]\t'magic2' is valid\n");
393 else
394 sig_print("[FAIL]\t'magic2' is not valid\n");
395
396 set_rand_data(&xstate, xbuf);
397 copy_xstate(stashed_xbuf, xbuf);
398 }
399
test_signal(void)400 static void test_signal(void)
401 {
402 bool valid_xstate;
403
404 /*
405 * The signal handler will access this to verify xstate context
406 * preservation.
407 */
408 stashed_xbuf = alloc_xbuf();
409 if (!stashed_xbuf)
410 ksft_exit_fail_msg("unable to allocate XSAVE buffer\n");
411
412 printf("[RUN]\t%s: load xstate and raise SIGUSR1\n", xstate.name);
413
414 sethandler(SIGUSR1, validate_sigfpstate, 0);
415
416 load_rand_xstate(&xstate, stashed_xbuf);
417
418 raise(SIGUSR1);
419
420 /*
421 * Immediately record the test result, deferring printf() to
422 * prevent unintended state contamination by that.
423 */
424 valid_xstate = validate_xregs_same(stashed_xbuf);
425 printf("%s", signal_message_buffer);
426
427 printf("[RUN]\t%s: load new xstate from sighandler and check it after sigreturn\n",
428 xstate.name);
429
430 if (valid_xstate)
431 printf("[OK]\txstate was restored correctly\n");
432 else
433 printf("[FAIL]\txstate restoration failed\n");
434
435 clearhandler(SIGUSR1);
436 free(stashed_xbuf);
437 }
438
test_xstate(uint32_t feature_num)439 void test_xstate(uint32_t feature_num)
440 {
441 const unsigned int ctxtsw_num_threads = 5, ctxtsw_iterations = 10;
442 unsigned long features;
443 long rc;
444
445 if (!(XFEATURE_MASK_TEST_SUPPORTED & (1 << feature_num))) {
446 ksft_print_msg("The xstate test does not fully support the component %u, yet.\n",
447 feature_num);
448 return;
449 }
450
451 rc = syscall(SYS_arch_prctl, ARCH_GET_XCOMP_SUPP, &features);
452 if (rc || !(features & (1 << feature_num))) {
453 ksft_print_msg("The kernel does not support feature number: %u\n", feature_num);
454 return;
455 }
456
457 xstate = get_xstate_info(feature_num);
458 if (!xstate.size || !xstate.xbuf_offset) {
459 ksft_exit_fail_msg("invalid state size/offset (%d/%d)\n",
460 xstate.size, xstate.xbuf_offset);
461 }
462
463 test_context_switch(ctxtsw_num_threads, ctxtsw_iterations);
464 test_ptrace();
465 test_signal();
466 }
467