1 // SPDX-License-Identifier: GPL-2.0
2 
3 #define _GNU_SOURCE
4 #include <err.h>
5 #include <errno.h>
6 #include <setjmp.h>
7 #include <stdio.h>
8 #include <string.h>
9 #include <stdbool.h>
10 #include <unistd.h>
11 #include <x86intrin.h>
12 
13 #include <sys/auxv.h>
14 #include <sys/mman.h>
15 #include <sys/shm.h>
16 #include <sys/syscall.h>
17 #include <sys/wait.h>
18 
19 #include "helpers.h"
20 #include "xstate.h"
21 
22 #ifndef __x86_64__
23 # error This test is 64-bit only
24 #endif
25 
26 /* err() exits and will not return */
27 #define fatal_error(msg, ...)	err(1, "[FAIL]\t" msg, ##__VA_ARGS__)
28 
29 #define XFEATURE_MASK_XTILECFG	(1 << XFEATURE_XTILECFG)
30 #define XFEATURE_MASK_XTILEDATA	(1 << XFEATURE_XTILEDATA)
31 #define XFEATURE_MASK_XTILE	(XFEATURE_MASK_XTILECFG | XFEATURE_MASK_XTILEDATA)
32 
33 struct xstate_info xtiledata;
34 
35 /* The helpers for managing XSAVE buffer and tile states: */
36 
37 struct xsave_buffer *stashed_xsave;
38 
init_stashed_xsave(void)39 static void init_stashed_xsave(void)
40 {
41 	stashed_xsave = alloc_xbuf();
42 	if (!stashed_xsave)
43 		fatal_error("failed to allocate stashed_xsave\n");
44 	clear_xstate_header(stashed_xsave);
45 }
46 
free_stashed_xsave(void)47 static void free_stashed_xsave(void)
48 {
49 	free(stashed_xsave);
50 }
51 
52 /* Work around printf() being unsafe in signals: */
53 #define SIGNAL_BUF_LEN 1000
54 char signal_message_buffer[SIGNAL_BUF_LEN];
sig_print(char * msg)55 void sig_print(char *msg)
56 {
57 	int left = SIGNAL_BUF_LEN - strlen(signal_message_buffer) - 1;
58 
59 	strncat(signal_message_buffer, msg, left);
60 }
61 
62 static volatile bool noperm_signaled;
63 static int noperm_errs;
64 /*
65  * Signal handler for when AMX is used but
66  * permission has not been obtained.
67  */
handle_noperm(int sig,siginfo_t * si,void * ctx_void)68 static void handle_noperm(int sig, siginfo_t *si, void *ctx_void)
69 {
70 	ucontext_t *ctx = (ucontext_t *)ctx_void;
71 	void *xbuf = ctx->uc_mcontext.fpregs;
72 	struct _fpx_sw_bytes *sw_bytes;
73 	uint64_t features;
74 
75 	/* Reset the signal message buffer: */
76 	signal_message_buffer[0] = '\0';
77 	sig_print("\tAt SIGILL handler,\n");
78 
79 	if (si->si_code != ILL_ILLOPC) {
80 		noperm_errs++;
81 		sig_print("[FAIL]\tInvalid signal code.\n");
82 	} else {
83 		sig_print("[OK]\tValid signal code (ILL_ILLOPC).\n");
84 	}
85 
86 	sw_bytes = get_fpx_sw_bytes(xbuf);
87 	/*
88 	 * Without permission, the signal XSAVE buffer should not
89 	 * have room for AMX register state (aka. xtiledata).
90 	 * Check that the size does not overlap with where xtiledata
91 	 * will reside.
92 	 *
93 	 * This also implies that no state components *PAST*
94 	 * XTILEDATA (features >=19) can be present in the buffer.
95 	 */
96 	if (sw_bytes->xstate_size <= xtiledata.xbuf_offset) {
97 		sig_print("[OK]\tValid xstate size\n");
98 	} else {
99 		noperm_errs++;
100 		sig_print("[FAIL]\tInvalid xstate size\n");
101 	}
102 
103 	features = get_fpx_sw_bytes_features(xbuf);
104 	/*
105 	 * Without permission, the XTILEDATA feature
106 	 * bit should not be set.
107 	 */
108 	if ((features & XFEATURE_MASK_XTILEDATA) == 0) {
109 		sig_print("[OK]\tValid xstate mask\n");
110 	} else {
111 		noperm_errs++;
112 		sig_print("[FAIL]\tInvalid xstate mask\n");
113 	}
114 
115 	noperm_signaled = true;
116 	ctx->uc_mcontext.gregs[REG_RIP] += 3; /* Skip the faulting XRSTOR */
117 }
118 
119 /* Return true if XRSTOR is successful; otherwise, false. */
xrstor_safe(struct xsave_buffer * xbuf,uint64_t mask)120 static inline bool xrstor_safe(struct xsave_buffer *xbuf, uint64_t mask)
121 {
122 	noperm_signaled = false;
123 	xrstor(xbuf, mask);
124 
125 	/* Print any messages produced by the signal code: */
126 	printf("%s", signal_message_buffer);
127 	/*
128 	 * Reset the buffer to make sure any future printing
129 	 * only outputs new messages:
130 	 */
131 	signal_message_buffer[0] = '\0';
132 
133 	if (noperm_errs)
134 		fatal_error("saw %d errors in noperm signal handler\n", noperm_errs);
135 
136 	return !noperm_signaled;
137 }
138 
139 /*
140  * Use XRSTOR to populate the XTILEDATA registers with
141  * random data.
142  *
143  * Return true if successful; otherwise, false.
144  */
load_rand_tiledata(struct xsave_buffer * xbuf)145 static inline bool load_rand_tiledata(struct xsave_buffer *xbuf)
146 {
147 	clear_xstate_header(xbuf);
148 	set_xstatebv(xbuf, XFEATURE_MASK_XTILEDATA);
149 	set_rand_data(&xtiledata, xbuf);
150 	return xrstor_safe(xbuf, XFEATURE_MASK_XTILEDATA);
151 }
152 
153 enum expected_result { FAIL_EXPECTED, SUCCESS_EXPECTED };
154 
155 /* arch_prctl() and sigaltstack() test */
156 
157 #define ARCH_GET_XCOMP_SUPP	0x1021
158 #define ARCH_GET_XCOMP_PERM	0x1022
159 #define ARCH_REQ_XCOMP_PERM	0x1023
160 
req_xtiledata_perm(void)161 static void req_xtiledata_perm(void)
162 {
163 	syscall(SYS_arch_prctl, ARCH_REQ_XCOMP_PERM, XFEATURE_XTILEDATA);
164 }
165 
validate_req_xcomp_perm(enum expected_result exp)166 static void validate_req_xcomp_perm(enum expected_result exp)
167 {
168 	unsigned long bitmask, expected_bitmask;
169 	long rc;
170 
171 	rc = syscall(SYS_arch_prctl, ARCH_GET_XCOMP_PERM, &bitmask);
172 	if (rc) {
173 		fatal_error("prctl(ARCH_GET_XCOMP_PERM) error: %ld", rc);
174 	} else if (!(bitmask & XFEATURE_MASK_XTILECFG)) {
175 		fatal_error("ARCH_GET_XCOMP_PERM returns XFEATURE_XTILECFG off.");
176 	}
177 
178 	rc = syscall(SYS_arch_prctl, ARCH_REQ_XCOMP_PERM, XFEATURE_XTILEDATA);
179 	if (exp == FAIL_EXPECTED) {
180 		if (rc) {
181 			printf("[OK]\tARCH_REQ_XCOMP_PERM saw expected failure..\n");
182 			return;
183 		}
184 
185 		fatal_error("ARCH_REQ_XCOMP_PERM saw unexpected success.\n");
186 	} else if (rc) {
187 		fatal_error("ARCH_REQ_XCOMP_PERM saw unexpected failure.\n");
188 	}
189 
190 	expected_bitmask = bitmask | XFEATURE_MASK_XTILEDATA;
191 
192 	rc = syscall(SYS_arch_prctl, ARCH_GET_XCOMP_PERM, &bitmask);
193 	if (rc) {
194 		fatal_error("prctl(ARCH_GET_XCOMP_PERM) error: %ld", rc);
195 	} else if (bitmask != expected_bitmask) {
196 		fatal_error("ARCH_REQ_XCOMP_PERM set a wrong bitmask: %lx, expected: %lx.\n",
197 			    bitmask, expected_bitmask);
198 	} else {
199 		printf("\tARCH_REQ_XCOMP_PERM is successful.\n");
200 	}
201 }
202 
validate_xcomp_perm(enum expected_result exp)203 static void validate_xcomp_perm(enum expected_result exp)
204 {
205 	bool load_success = load_rand_tiledata(stashed_xsave);
206 
207 	if (exp == FAIL_EXPECTED) {
208 		if (load_success) {
209 			noperm_errs++;
210 			printf("[FAIL]\tLoad tiledata succeeded.\n");
211 		} else {
212 			printf("[OK]\tLoad tiledata failed.\n");
213 		}
214 	} else if (exp == SUCCESS_EXPECTED) {
215 		if (load_success) {
216 			printf("[OK]\tLoad tiledata succeeded.\n");
217 		} else {
218 			noperm_errs++;
219 			printf("[FAIL]\tLoad tiledata failed.\n");
220 		}
221 	}
222 }
223 
224 #ifndef AT_MINSIGSTKSZ
225 #  define AT_MINSIGSTKSZ	51
226 #endif
227 
alloc_altstack(unsigned int size)228 static void *alloc_altstack(unsigned int size)
229 {
230 	void *altstack;
231 
232 	altstack = mmap(NULL, size, PROT_READ | PROT_WRITE,
233 			MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0);
234 
235 	if (altstack == MAP_FAILED)
236 		fatal_error("mmap() for altstack");
237 
238 	return altstack;
239 }
240 
setup_altstack(void * addr,unsigned long size,enum expected_result exp)241 static void setup_altstack(void *addr, unsigned long size, enum expected_result exp)
242 {
243 	stack_t ss;
244 	int rc;
245 
246 	memset(&ss, 0, sizeof(ss));
247 	ss.ss_size = size;
248 	ss.ss_sp = addr;
249 
250 	rc = sigaltstack(&ss, NULL);
251 
252 	if (exp == FAIL_EXPECTED) {
253 		if (rc) {
254 			printf("[OK]\tsigaltstack() failed.\n");
255 		} else {
256 			fatal_error("sigaltstack() succeeded unexpectedly.\n");
257 		}
258 	} else if (rc) {
259 		fatal_error("sigaltstack()");
260 	}
261 }
262 
test_dynamic_sigaltstack(void)263 static void test_dynamic_sigaltstack(void)
264 {
265 	unsigned int small_size, enough_size;
266 	unsigned long minsigstksz;
267 	void *altstack;
268 
269 	minsigstksz = getauxval(AT_MINSIGSTKSZ);
270 	printf("\tAT_MINSIGSTKSZ = %lu\n", minsigstksz);
271 	/*
272 	 * getauxval() itself can return 0 for failure or
273 	 * success.  But, in this case, AT_MINSIGSTKSZ
274 	 * will always return a >=0 value if implemented.
275 	 * Just check for 0.
276 	 */
277 	if (minsigstksz == 0) {
278 		printf("no support for AT_MINSIGSTKSZ, skipping sigaltstack tests\n");
279 		return;
280 	}
281 
282 	enough_size = minsigstksz * 2;
283 
284 	altstack = alloc_altstack(enough_size);
285 	printf("\tAllocate memory for altstack (%u bytes).\n", enough_size);
286 
287 	/*
288 	 * Try setup_altstack() with a size which can not fit
289 	 * XTILEDATA.  ARCH_REQ_XCOMP_PERM should fail.
290 	 */
291 	small_size = minsigstksz - xtiledata.size;
292 	printf("\tAfter sigaltstack() with small size (%u bytes).\n", small_size);
293 	setup_altstack(altstack, small_size, SUCCESS_EXPECTED);
294 	validate_req_xcomp_perm(FAIL_EXPECTED);
295 
296 	/*
297 	 * Try setup_altstack() with a size derived from
298 	 * AT_MINSIGSTKSZ.  It should be more than large enough
299 	 * and thus ARCH_REQ_XCOMP_PERM should succeed.
300 	 */
301 	printf("\tAfter sigaltstack() with enough size (%u bytes).\n", enough_size);
302 	setup_altstack(altstack, enough_size, SUCCESS_EXPECTED);
303 	validate_req_xcomp_perm(SUCCESS_EXPECTED);
304 
305 	/*
306 	 * Try to coerce setup_altstack() to again accept a
307 	 * too-small altstack.  This ensures that big-enough
308 	 * sigaltstacks can not shrink to a too-small value
309 	 * once XTILEDATA permission is established.
310 	 */
311 	printf("\tThen, sigaltstack() with small size (%u bytes).\n", small_size);
312 	setup_altstack(altstack, small_size, FAIL_EXPECTED);
313 }
314 
test_dynamic_state(void)315 static void test_dynamic_state(void)
316 {
317 	pid_t parent, child, grandchild;
318 
319 	parent = fork();
320 	if (parent < 0) {
321 		/* fork() failed */
322 		fatal_error("fork");
323 	} else if (parent > 0) {
324 		int status;
325 		/* fork() succeeded.  Now in the parent. */
326 
327 		wait(&status);
328 		if (!WIFEXITED(status) || WEXITSTATUS(status))
329 			fatal_error("arch_prctl test parent exit");
330 		return;
331 	}
332 	/* fork() succeeded.  Now in the child . */
333 
334 	printf("[RUN]\tCheck ARCH_REQ_XCOMP_PERM around process fork() and sigaltack() test.\n");
335 
336 	printf("\tFork a child.\n");
337 	child = fork();
338 	if (child < 0) {
339 		fatal_error("fork");
340 	} else if (child > 0) {
341 		int status;
342 
343 		wait(&status);
344 		if (!WIFEXITED(status) || WEXITSTATUS(status))
345 			fatal_error("arch_prctl test child exit");
346 		_exit(0);
347 	}
348 
349 	/*
350 	 * The permission request should fail without an
351 	 * XTILEDATA-compatible signal stack
352 	 */
353 	printf("\tTest XCOMP_PERM at child.\n");
354 	validate_xcomp_perm(FAIL_EXPECTED);
355 
356 	/*
357 	 * Set up an XTILEDATA-compatible signal stack and
358 	 * also obtain permission to populate XTILEDATA.
359 	 */
360 	printf("\tTest dynamic sigaltstack at child:\n");
361 	test_dynamic_sigaltstack();
362 
363 	/* Ensure that XTILEDATA can be populated. */
364 	printf("\tTest XCOMP_PERM again at child.\n");
365 	validate_xcomp_perm(SUCCESS_EXPECTED);
366 
367 	printf("\tFork a grandchild.\n");
368 	grandchild = fork();
369 	if (grandchild < 0) {
370 		/* fork() failed */
371 		fatal_error("fork");
372 	} else if (!grandchild) {
373 		/* fork() succeeded.  Now in the (grand)child. */
374 		printf("\tTest XCOMP_PERM at grandchild.\n");
375 
376 		/*
377 		 * Ensure that the grandchild inherited
378 		 * permission and a compatible sigaltstack:
379 		 */
380 		validate_xcomp_perm(SUCCESS_EXPECTED);
381 	} else {
382 		int status;
383 		/* fork() succeeded.  Now in the parent. */
384 
385 		wait(&status);
386 		if (!WIFEXITED(status) || WEXITSTATUS(status))
387 			fatal_error("fork test grandchild");
388 	}
389 
390 	_exit(0);
391 }
392 
__compare_tiledata_state(struct xsave_buffer * xbuf1,struct xsave_buffer * xbuf2)393 static inline int __compare_tiledata_state(struct xsave_buffer *xbuf1, struct xsave_buffer *xbuf2)
394 {
395 	return memcmp(&xbuf1->bytes[xtiledata.xbuf_offset],
396 		      &xbuf2->bytes[xtiledata.xbuf_offset],
397 		      xtiledata.size);
398 }
399 
400 /*
401  * Save current register state and compare it to @xbuf1.'
402  *
403  * Returns false if @xbuf1 matches the registers.
404  * Returns true  if @xbuf1 differs from the registers.
405  */
__validate_tiledata_regs(struct xsave_buffer * xbuf1)406 static inline bool __validate_tiledata_regs(struct xsave_buffer *xbuf1)
407 {
408 	struct xsave_buffer *xbuf2;
409 	int ret;
410 
411 	xbuf2 = alloc_xbuf();
412 	if (!xbuf2)
413 		fatal_error("failed to allocate XSAVE buffer\n");
414 
415 	xsave(xbuf2, XFEATURE_MASK_XTILEDATA);
416 	ret = __compare_tiledata_state(xbuf1, xbuf2);
417 
418 	free(xbuf2);
419 
420 	if (ret == 0)
421 		return false;
422 	return true;
423 }
424 
validate_tiledata_regs_changed(struct xsave_buffer * xbuf)425 static inline void validate_tiledata_regs_changed(struct xsave_buffer *xbuf)
426 {
427 	int ret = __validate_tiledata_regs(xbuf);
428 
429 	if (ret == 0)
430 		fatal_error("TILEDATA registers did not change");
431 }
432 
433 /* tiledata inheritance test */
434 
test_fork(void)435 static void test_fork(void)
436 {
437 	pid_t child, grandchild;
438 
439 	child = fork();
440 	if (child < 0) {
441 		/* fork() failed */
442 		fatal_error("fork");
443 	} else if (child > 0) {
444 		/* fork() succeeded.  Now in the parent. */
445 		int status;
446 
447 		wait(&status);
448 		if (!WIFEXITED(status) || WEXITSTATUS(status))
449 			fatal_error("fork test child");
450 		return;
451 	}
452 	/* fork() succeeded.  Now in the child. */
453 	printf("[RUN]\tCheck tile data inheritance.\n\tBefore fork(), load tiledata\n");
454 
455 	load_rand_tiledata(stashed_xsave);
456 
457 	grandchild = fork();
458 	if (grandchild < 0) {
459 		/* fork() failed */
460 		fatal_error("fork");
461 	} else if (grandchild > 0) {
462 		/* fork() succeeded.  Still in the first child. */
463 		int status;
464 
465 		wait(&status);
466 		if (!WIFEXITED(status) || WEXITSTATUS(status))
467 			fatal_error("fork test grand child");
468 		_exit(0);
469 	}
470 	/* fork() succeeded.  Now in the (grand)child. */
471 
472 	/*
473 	 * TILEDATA registers are not preserved across fork().
474 	 * Ensure that their value has changed:
475 	 */
476 	validate_tiledata_regs_changed(stashed_xsave);
477 
478 	_exit(0);
479 }
480 
main(void)481 int main(void)
482 {
483 	unsigned long features;
484 	long rc;
485 
486 	rc = syscall(SYS_arch_prctl, ARCH_GET_XCOMP_SUPP, &features);
487 	if (rc || (features & XFEATURE_MASK_XTILE) != XFEATURE_MASK_XTILE) {
488 		ksft_print_msg("no AMX support\n");
489 		return KSFT_SKIP;
490 	}
491 
492 	xtiledata = get_xstate_info(XFEATURE_XTILEDATA);
493 	if (!xtiledata.size || !xtiledata.xbuf_offset) {
494 		fatal_error("xstate cpuid: invalid tile data size/offset: %d/%d",
495 			    xtiledata.size, xtiledata.xbuf_offset);
496 	}
497 
498 	init_stashed_xsave();
499 	sethandler(SIGILL, handle_noperm, 0);
500 
501 	test_dynamic_state();
502 
503 	/* Request permission for the following tests */
504 	req_xtiledata_perm();
505 
506 	test_fork();
507 
508 	/*
509 	 * Perform generic xstate tests for context switching, ptrace,
510 	 * and signal.
511 	 */
512 	test_xstate(XFEATURE_XTILEDATA);
513 
514 	clearhandler(SIGILL);
515 	free_stashed_xsave();
516 
517 	return 0;
518 }
519