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