xref: /openbmc/linux/tools/testing/selftests/x86/ldt_gdt.c (revision b24413180f5600bcb3bb70fbed5cf186b60864bd)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * ldt_gdt.c - Test cases for LDT and GDT access
4  * Copyright (c) 2015 Andrew Lutomirski
5  */
6 
7 #define _GNU_SOURCE
8 #include <err.h>
9 #include <stdio.h>
10 #include <stdint.h>
11 #include <signal.h>
12 #include <setjmp.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <errno.h>
16 #include <unistd.h>
17 #include <sys/syscall.h>
18 #include <asm/ldt.h>
19 #include <sys/types.h>
20 #include <sys/wait.h>
21 #include <stdbool.h>
22 #include <pthread.h>
23 #include <sched.h>
24 #include <linux/futex.h>
25 #include <sys/mman.h>
26 #include <asm/prctl.h>
27 #include <sys/prctl.h>
28 
29 #define AR_ACCESSED		(1<<8)
30 
31 #define AR_TYPE_RODATA		(0 * (1<<9))
32 #define AR_TYPE_RWDATA		(1 * (1<<9))
33 #define AR_TYPE_RODATA_EXPDOWN	(2 * (1<<9))
34 #define AR_TYPE_RWDATA_EXPDOWN	(3 * (1<<9))
35 #define AR_TYPE_XOCODE		(4 * (1<<9))
36 #define AR_TYPE_XRCODE		(5 * (1<<9))
37 #define AR_TYPE_XOCODE_CONF	(6 * (1<<9))
38 #define AR_TYPE_XRCODE_CONF	(7 * (1<<9))
39 
40 #define AR_DPL3			(3 * (1<<13))
41 
42 #define AR_S			(1 << 12)
43 #define AR_P			(1 << 15)
44 #define AR_AVL			(1 << 20)
45 #define AR_L			(1 << 21)
46 #define AR_DB			(1 << 22)
47 #define AR_G			(1 << 23)
48 
49 #ifdef __x86_64__
50 # define INT80_CLOBBERS "r8", "r9", "r10", "r11"
51 #else
52 # define INT80_CLOBBERS
53 #endif
54 
55 static int nerrs;
56 
57 /* Points to an array of 1024 ints, each holding its own index. */
58 static const unsigned int *counter_page;
59 static struct user_desc *low_user_desc;
60 static struct user_desc *low_user_desc_clear;  /* Use to delete GDT entry */
61 static int gdt_entry_num;
62 
63 static void check_invalid_segment(uint16_t index, int ldt)
64 {
65 	uint32_t has_limit = 0, has_ar = 0, limit, ar;
66 	uint32_t selector = (index << 3) | (ldt << 2) | 3;
67 
68 	asm ("lsl %[selector], %[limit]\n\t"
69 	     "jnz 1f\n\t"
70 	     "movl $1, %[has_limit]\n\t"
71 	     "1:"
72 	     : [limit] "=r" (limit), [has_limit] "+rm" (has_limit)
73 	     : [selector] "r" (selector));
74 	asm ("larl %[selector], %[ar]\n\t"
75 	     "jnz 1f\n\t"
76 	     "movl $1, %[has_ar]\n\t"
77 	     "1:"
78 	     : [ar] "=r" (ar), [has_ar] "+rm" (has_ar)
79 	     : [selector] "r" (selector));
80 
81 	if (has_limit || has_ar) {
82 		printf("[FAIL]\t%s entry %hu is valid but should be invalid\n",
83 		       (ldt ? "LDT" : "GDT"), index);
84 		nerrs++;
85 	} else {
86 		printf("[OK]\t%s entry %hu is invalid\n",
87 		       (ldt ? "LDT" : "GDT"), index);
88 	}
89 }
90 
91 static void check_valid_segment(uint16_t index, int ldt,
92 				uint32_t expected_ar, uint32_t expected_limit,
93 				bool verbose)
94 {
95 	uint32_t has_limit = 0, has_ar = 0, limit, ar;
96 	uint32_t selector = (index << 3) | (ldt << 2) | 3;
97 
98 	asm ("lsl %[selector], %[limit]\n\t"
99 	     "jnz 1f\n\t"
100 	     "movl $1, %[has_limit]\n\t"
101 	     "1:"
102 	     : [limit] "=r" (limit), [has_limit] "+rm" (has_limit)
103 	     : [selector] "r" (selector));
104 	asm ("larl %[selector], %[ar]\n\t"
105 	     "jnz 1f\n\t"
106 	     "movl $1, %[has_ar]\n\t"
107 	     "1:"
108 	     : [ar] "=r" (ar), [has_ar] "+rm" (has_ar)
109 	     : [selector] "r" (selector));
110 
111 	if (!has_limit || !has_ar) {
112 		printf("[FAIL]\t%s entry %hu is invalid but should be valid\n",
113 		       (ldt ? "LDT" : "GDT"), index);
114 		nerrs++;
115 		return;
116 	}
117 
118 	if (ar != expected_ar) {
119 		printf("[FAIL]\t%s entry %hu has AR 0x%08X but expected 0x%08X\n",
120 		       (ldt ? "LDT" : "GDT"), index, ar, expected_ar);
121 		nerrs++;
122 	} else if (limit != expected_limit) {
123 		printf("[FAIL]\t%s entry %hu has limit 0x%08X but expected 0x%08X\n",
124 		       (ldt ? "LDT" : "GDT"), index, limit, expected_limit);
125 		nerrs++;
126 	} else if (verbose) {
127 		printf("[OK]\t%s entry %hu has AR 0x%08X and limit 0x%08X\n",
128 		       (ldt ? "LDT" : "GDT"), index, ar, limit);
129 	}
130 }
131 
132 static bool install_valid_mode(const struct user_desc *desc, uint32_t ar,
133 			       bool oldmode)
134 {
135 	int ret = syscall(SYS_modify_ldt, oldmode ? 1 : 0x11,
136 			  desc, sizeof(*desc));
137 	if (ret < -1)
138 		errno = -ret;
139 	if (ret == 0) {
140 		uint32_t limit = desc->limit;
141 		if (desc->limit_in_pages)
142 			limit = (limit << 12) + 4095;
143 		check_valid_segment(desc->entry_number, 1, ar, limit, true);
144 		return true;
145 	} else if (errno == ENOSYS) {
146 		printf("[OK]\tmodify_ldt returned -ENOSYS\n");
147 		return false;
148 	} else {
149 		if (desc->seg_32bit) {
150 			printf("[FAIL]\tUnexpected modify_ldt failure %d\n",
151 			       errno);
152 			nerrs++;
153 			return false;
154 		} else {
155 			printf("[OK]\tmodify_ldt rejected 16 bit segment\n");
156 			return false;
157 		}
158 	}
159 }
160 
161 static bool install_valid(const struct user_desc *desc, uint32_t ar)
162 {
163 	return install_valid_mode(desc, ar, false);
164 }
165 
166 static void install_invalid(const struct user_desc *desc, bool oldmode)
167 {
168 	int ret = syscall(SYS_modify_ldt, oldmode ? 1 : 0x11,
169 			  desc, sizeof(*desc));
170 	if (ret < -1)
171 		errno = -ret;
172 	if (ret == 0) {
173 		check_invalid_segment(desc->entry_number, 1);
174 	} else if (errno == ENOSYS) {
175 		printf("[OK]\tmodify_ldt returned -ENOSYS\n");
176 	} else {
177 		if (desc->seg_32bit) {
178 			printf("[FAIL]\tUnexpected modify_ldt failure %d\n",
179 			       errno);
180 			nerrs++;
181 		} else {
182 			printf("[OK]\tmodify_ldt rejected 16 bit segment\n");
183 		}
184 	}
185 }
186 
187 static int safe_modify_ldt(int func, struct user_desc *ptr,
188 			   unsigned long bytecount)
189 {
190 	int ret = syscall(SYS_modify_ldt, 0x11, ptr, bytecount);
191 	if (ret < -1)
192 		errno = -ret;
193 	return ret;
194 }
195 
196 static void fail_install(struct user_desc *desc)
197 {
198 	if (safe_modify_ldt(0x11, desc, sizeof(*desc)) == 0) {
199 		printf("[FAIL]\tmodify_ldt accepted a bad descriptor\n");
200 		nerrs++;
201 	} else if (errno == ENOSYS) {
202 		printf("[OK]\tmodify_ldt returned -ENOSYS\n");
203 	} else {
204 		printf("[OK]\tmodify_ldt failure %d\n", errno);
205 	}
206 }
207 
208 static void do_simple_tests(void)
209 {
210 	struct user_desc desc = {
211 		.entry_number    = 0,
212 		.base_addr       = 0,
213 		.limit           = 10,
214 		.seg_32bit       = 1,
215 		.contents        = 2, /* Code, not conforming */
216 		.read_exec_only  = 0,
217 		.limit_in_pages  = 0,
218 		.seg_not_present = 0,
219 		.useable         = 0
220 	};
221 	install_valid(&desc, AR_DPL3 | AR_TYPE_XRCODE | AR_S | AR_P | AR_DB);
222 
223 	desc.limit_in_pages = 1;
224 	install_valid(&desc, AR_DPL3 | AR_TYPE_XRCODE |
225 		      AR_S | AR_P | AR_DB | AR_G);
226 
227 	check_invalid_segment(1, 1);
228 
229 	desc.entry_number = 2;
230 	install_valid(&desc, AR_DPL3 | AR_TYPE_XRCODE |
231 		      AR_S | AR_P | AR_DB | AR_G);
232 
233 	check_invalid_segment(1, 1);
234 
235 	desc.base_addr = 0xf0000000;
236 	install_valid(&desc, AR_DPL3 | AR_TYPE_XRCODE |
237 		      AR_S | AR_P | AR_DB | AR_G);
238 
239 	desc.useable = 1;
240 	install_valid(&desc, AR_DPL3 | AR_TYPE_XRCODE |
241 		      AR_S | AR_P | AR_DB | AR_G | AR_AVL);
242 
243 	desc.seg_not_present = 1;
244 	install_valid(&desc, AR_DPL3 | AR_TYPE_XRCODE |
245 		      AR_S | AR_DB | AR_G | AR_AVL);
246 
247 	desc.seg_32bit = 0;
248 	install_valid(&desc, AR_DPL3 | AR_TYPE_XRCODE |
249 		      AR_S | AR_G | AR_AVL);
250 
251 	desc.seg_32bit = 1;
252 	desc.contents = 0;
253 	install_valid(&desc, AR_DPL3 | AR_TYPE_RWDATA |
254 		      AR_S | AR_DB | AR_G | AR_AVL);
255 
256 	desc.read_exec_only = 1;
257 	install_valid(&desc, AR_DPL3 | AR_TYPE_RODATA |
258 		      AR_S | AR_DB | AR_G | AR_AVL);
259 
260 	desc.contents = 1;
261 	install_valid(&desc, AR_DPL3 | AR_TYPE_RODATA_EXPDOWN |
262 		      AR_S | AR_DB | AR_G | AR_AVL);
263 
264 	desc.read_exec_only = 0;
265 	desc.limit_in_pages = 0;
266 	install_valid(&desc, AR_DPL3 | AR_TYPE_RWDATA_EXPDOWN |
267 		      AR_S | AR_DB | AR_AVL);
268 
269 	desc.contents = 3;
270 	install_valid(&desc, AR_DPL3 | AR_TYPE_XRCODE_CONF |
271 		      AR_S | AR_DB | AR_AVL);
272 
273 	desc.read_exec_only = 1;
274 	install_valid(&desc, AR_DPL3 | AR_TYPE_XOCODE_CONF |
275 		      AR_S | AR_DB | AR_AVL);
276 
277 	desc.read_exec_only = 0;
278 	desc.contents = 2;
279 	install_valid(&desc, AR_DPL3 | AR_TYPE_XRCODE |
280 		      AR_S | AR_DB | AR_AVL);
281 
282 	desc.read_exec_only = 1;
283 
284 #ifdef __x86_64__
285 	desc.lm = 1;
286 	install_valid(&desc, AR_DPL3 | AR_TYPE_XOCODE |
287 		      AR_S | AR_DB | AR_AVL);
288 	desc.lm = 0;
289 #endif
290 
291 	bool entry1_okay = install_valid(&desc, AR_DPL3 | AR_TYPE_XOCODE |
292 					 AR_S | AR_DB | AR_AVL);
293 
294 	if (entry1_okay) {
295 		printf("[RUN]\tTest fork\n");
296 		pid_t child = fork();
297 		if (child == 0) {
298 			nerrs = 0;
299 			check_valid_segment(desc.entry_number, 1,
300 					    AR_DPL3 | AR_TYPE_XOCODE |
301 					    AR_S | AR_DB | AR_AVL, desc.limit,
302 					    true);
303 			check_invalid_segment(1, 1);
304 			exit(nerrs ? 1 : 0);
305 		} else {
306 			int status;
307 			if (waitpid(child, &status, 0) != child ||
308 			    !WIFEXITED(status)) {
309 				printf("[FAIL]\tChild died\n");
310 				nerrs++;
311 			} else if (WEXITSTATUS(status) != 0) {
312 				printf("[FAIL]\tChild failed\n");
313 				nerrs++;
314 			} else {
315 				printf("[OK]\tChild succeeded\n");
316 			}
317 		}
318 
319 		printf("[RUN]\tTest size\n");
320 		int i;
321 		for (i = 0; i < 8192; i++) {
322 			desc.entry_number = i;
323 			desc.limit = i;
324 			if (safe_modify_ldt(0x11, &desc, sizeof(desc)) != 0) {
325 				printf("[FAIL]\tFailed to install entry %d\n", i);
326 				nerrs++;
327 				break;
328 			}
329 		}
330 		for (int j = 0; j < i; j++) {
331 			check_valid_segment(j, 1, AR_DPL3 | AR_TYPE_XOCODE |
332 					    AR_S | AR_DB | AR_AVL, j, false);
333 		}
334 		printf("[DONE]\tSize test\n");
335 	} else {
336 		printf("[SKIP]\tSkipping fork and size tests because we have no LDT\n");
337 	}
338 
339 	/* Test entry_number too high. */
340 	desc.entry_number = 8192;
341 	fail_install(&desc);
342 
343 	/* Test deletion and actions mistakeable for deletion. */
344 	memset(&desc, 0, sizeof(desc));
345 	install_valid(&desc, AR_DPL3 | AR_TYPE_RWDATA | AR_S | AR_P);
346 
347 	desc.seg_not_present = 1;
348 	install_valid(&desc, AR_DPL3 | AR_TYPE_RWDATA | AR_S);
349 
350 	desc.seg_not_present = 0;
351 	desc.read_exec_only = 1;
352 	install_valid(&desc, AR_DPL3 | AR_TYPE_RODATA | AR_S | AR_P);
353 
354 	desc.read_exec_only = 0;
355 	desc.seg_not_present = 1;
356 	install_valid(&desc, AR_DPL3 | AR_TYPE_RWDATA | AR_S);
357 
358 	desc.read_exec_only = 1;
359 	desc.limit = 1;
360 	install_valid(&desc, AR_DPL3 | AR_TYPE_RODATA | AR_S);
361 
362 	desc.limit = 0;
363 	desc.base_addr = 1;
364 	install_valid(&desc, AR_DPL3 | AR_TYPE_RODATA | AR_S);
365 
366 	desc.base_addr = 0;
367 	install_invalid(&desc, false);
368 
369 	desc.seg_not_present = 0;
370 	desc.read_exec_only = 0;
371 	desc.seg_32bit = 1;
372 	install_valid(&desc, AR_DPL3 | AR_TYPE_RWDATA | AR_S | AR_P | AR_DB);
373 	install_invalid(&desc, true);
374 }
375 
376 /*
377  * 0: thread is idle
378  * 1: thread armed
379  * 2: thread should clear LDT entry 0
380  * 3: thread should exit
381  */
382 static volatile unsigned int ftx;
383 
384 static void *threadproc(void *ctx)
385 {
386 	cpu_set_t cpuset;
387 	CPU_ZERO(&cpuset);
388 	CPU_SET(1, &cpuset);
389 	if (sched_setaffinity(0, sizeof(cpuset), &cpuset) != 0)
390 		err(1, "sched_setaffinity to CPU 1");	/* should never fail */
391 
392 	while (1) {
393 		syscall(SYS_futex, &ftx, FUTEX_WAIT, 0, NULL, NULL, 0);
394 		while (ftx != 2) {
395 			if (ftx >= 3)
396 				return NULL;
397 		}
398 
399 		/* clear LDT entry 0 */
400 		const struct user_desc desc = {};
401 		if (syscall(SYS_modify_ldt, 1, &desc, sizeof(desc)) != 0)
402 			err(1, "modify_ldt");
403 
404 		/* If ftx == 2, set it to zero.  If ftx == 100, quit. */
405 		unsigned int x = -2;
406 		asm volatile ("lock xaddl %[x], %[ftx]" :
407 			      [x] "+r" (x), [ftx] "+m" (ftx));
408 		if (x != 2)
409 			return NULL;
410 	}
411 }
412 
413 #ifdef __i386__
414 
415 #ifndef SA_RESTORE
416 #define SA_RESTORER 0x04000000
417 #endif
418 
419 /*
420  * The UAPI header calls this 'struct sigaction', which conflicts with
421  * glibc.  Sigh.
422  */
423 struct fake_ksigaction {
424 	void *handler;  /* the real type is nasty */
425 	unsigned long sa_flags;
426 	void (*sa_restorer)(void);
427 	unsigned char sigset[8];
428 };
429 
430 static void fix_sa_restorer(int sig)
431 {
432 	struct fake_ksigaction ksa;
433 
434 	if (syscall(SYS_rt_sigaction, sig, NULL, &ksa, 8) == 0) {
435 		/*
436 		 * glibc has a nasty bug: it sometimes writes garbage to
437 		 * sa_restorer.  This interacts quite badly with anything
438 		 * that fiddles with SS because it can trigger legacy
439 		 * stack switching.  Patch it up.  See:
440 		 *
441 		 * https://sourceware.org/bugzilla/show_bug.cgi?id=21269
442 		 */
443 		if (!(ksa.sa_flags & SA_RESTORER) && ksa.sa_restorer) {
444 			ksa.sa_restorer = NULL;
445 			if (syscall(SYS_rt_sigaction, sig, &ksa, NULL,
446 				    sizeof(ksa.sigset)) != 0)
447 				err(1, "rt_sigaction");
448 		}
449 	}
450 }
451 #else
452 static void fix_sa_restorer(int sig)
453 {
454 	/* 64-bit glibc works fine. */
455 }
456 #endif
457 
458 static void sethandler(int sig, void (*handler)(int, siginfo_t *, void *),
459 		       int flags)
460 {
461 	struct sigaction sa;
462 	memset(&sa, 0, sizeof(sa));
463 	sa.sa_sigaction = handler;
464 	sa.sa_flags = SA_SIGINFO | flags;
465 	sigemptyset(&sa.sa_mask);
466 	if (sigaction(sig, &sa, 0))
467 		err(1, "sigaction");
468 
469 	fix_sa_restorer(sig);
470 }
471 
472 static jmp_buf jmpbuf;
473 
474 static void sigsegv(int sig, siginfo_t *info, void *ctx_void)
475 {
476 	siglongjmp(jmpbuf, 1);
477 }
478 
479 static void do_multicpu_tests(void)
480 {
481 	cpu_set_t cpuset;
482 	pthread_t thread;
483 	int failures = 0, iters = 5, i;
484 	unsigned short orig_ss;
485 
486 	CPU_ZERO(&cpuset);
487 	CPU_SET(1, &cpuset);
488 	if (sched_setaffinity(0, sizeof(cpuset), &cpuset) != 0) {
489 		printf("[SKIP]\tCannot set affinity to CPU 1\n");
490 		return;
491 	}
492 
493 	CPU_ZERO(&cpuset);
494 	CPU_SET(0, &cpuset);
495 	if (sched_setaffinity(0, sizeof(cpuset), &cpuset) != 0) {
496 		printf("[SKIP]\tCannot set affinity to CPU 0\n");
497 		return;
498 	}
499 
500 	sethandler(SIGSEGV, sigsegv, 0);
501 #ifdef __i386__
502 	/* True 32-bit kernels send SIGILL instead of SIGSEGV on IRET faults. */
503 	sethandler(SIGILL, sigsegv, 0);
504 #endif
505 
506 	printf("[RUN]\tCross-CPU LDT invalidation\n");
507 
508 	if (pthread_create(&thread, 0, threadproc, 0) != 0)
509 		err(1, "pthread_create");
510 
511 	asm volatile ("mov %%ss, %0" : "=rm" (orig_ss));
512 
513 	for (i = 0; i < 5; i++) {
514 		if (sigsetjmp(jmpbuf, 1) != 0)
515 			continue;
516 
517 		/* Make sure the thread is ready after the last test. */
518 		while (ftx != 0)
519 			;
520 
521 		struct user_desc desc = {
522 			.entry_number    = 0,
523 			.base_addr       = 0,
524 			.limit           = 0xfffff,
525 			.seg_32bit       = 1,
526 			.contents        = 0, /* Data */
527 			.read_exec_only  = 0,
528 			.limit_in_pages  = 1,
529 			.seg_not_present = 0,
530 			.useable         = 0
531 		};
532 
533 		if (safe_modify_ldt(0x11, &desc, sizeof(desc)) != 0) {
534 			if (errno != ENOSYS)
535 				err(1, "modify_ldt");
536 			printf("[SKIP]\tmodify_ldt unavailable\n");
537 			break;
538 		}
539 
540 		/* Arm the thread. */
541 		ftx = 1;
542 		syscall(SYS_futex, &ftx, FUTEX_WAKE, 0, NULL, NULL, 0);
543 
544 		asm volatile ("mov %0, %%ss" : : "r" (0x7));
545 
546 		/* Go! */
547 		ftx = 2;
548 
549 		while (ftx != 0)
550 			;
551 
552 		/*
553 		 * On success, modify_ldt will segfault us synchronously,
554 		 * and we'll escape via siglongjmp.
555 		 */
556 
557 		failures++;
558 		asm volatile ("mov %0, %%ss" : : "rm" (orig_ss));
559 	};
560 
561 	ftx = 100;  /* Kill the thread. */
562 	syscall(SYS_futex, &ftx, FUTEX_WAKE, 0, NULL, NULL, 0);
563 
564 	if (pthread_join(thread, NULL) != 0)
565 		err(1, "pthread_join");
566 
567 	if (failures) {
568 		printf("[FAIL]\t%d of %d iterations failed\n", failures, iters);
569 		nerrs++;
570 	} else {
571 		printf("[OK]\tAll %d iterations succeeded\n", iters);
572 	}
573 }
574 
575 static int finish_exec_test(void)
576 {
577 	/*
578 	 * In a sensible world, this would be check_invalid_segment(0, 1);
579 	 * For better or for worse, though, the LDT is inherited across exec.
580 	 * We can probably change this safely, but for now we test it.
581 	 */
582 	check_valid_segment(0, 1,
583 			    AR_DPL3 | AR_TYPE_XRCODE | AR_S | AR_P | AR_DB,
584 			    42, true);
585 
586 	return nerrs ? 1 : 0;
587 }
588 
589 static void do_exec_test(void)
590 {
591 	printf("[RUN]\tTest exec\n");
592 
593 	struct user_desc desc = {
594 		.entry_number    = 0,
595 		.base_addr       = 0,
596 		.limit           = 42,
597 		.seg_32bit       = 1,
598 		.contents        = 2, /* Code, not conforming */
599 		.read_exec_only  = 0,
600 		.limit_in_pages  = 0,
601 		.seg_not_present = 0,
602 		.useable         = 0
603 	};
604 	install_valid(&desc, AR_DPL3 | AR_TYPE_XRCODE | AR_S | AR_P | AR_DB);
605 
606 	pid_t child = fork();
607 	if (child == 0) {
608 		execl("/proc/self/exe", "ldt_gdt_test_exec", NULL);
609 		printf("[FAIL]\tCould not exec self\n");
610 		exit(1);	/* exec failed */
611 	} else {
612 		int status;
613 		if (waitpid(child, &status, 0) != child ||
614 		    !WIFEXITED(status)) {
615 			printf("[FAIL]\tChild died\n");
616 			nerrs++;
617 		} else if (WEXITSTATUS(status) != 0) {
618 			printf("[FAIL]\tChild failed\n");
619 			nerrs++;
620 		} else {
621 			printf("[OK]\tChild succeeded\n");
622 		}
623 	}
624 }
625 
626 static void setup_counter_page(void)
627 {
628 	unsigned int *page = mmap(NULL, 4096, PROT_READ | PROT_WRITE,
629 			 MAP_ANONYMOUS | MAP_PRIVATE | MAP_32BIT, -1, 0);
630 	if (page == MAP_FAILED)
631 		err(1, "mmap");
632 
633 	for (int i = 0; i < 1024; i++)
634 		page[i] = i;
635 	counter_page = page;
636 }
637 
638 static int invoke_set_thread_area(void)
639 {
640 	int ret;
641 	asm volatile ("int $0x80"
642 		      : "=a" (ret), "+m" (low_user_desc) :
643 			"a" (243), "b" (low_user_desc)
644 		      : INT80_CLOBBERS);
645 	return ret;
646 }
647 
648 static void setup_low_user_desc(void)
649 {
650 	low_user_desc = mmap(NULL, 2 * sizeof(struct user_desc),
651 			     PROT_READ | PROT_WRITE,
652 			     MAP_ANONYMOUS | MAP_PRIVATE | MAP_32BIT, -1, 0);
653 	if (low_user_desc == MAP_FAILED)
654 		err(1, "mmap");
655 
656 	low_user_desc->entry_number	= -1;
657 	low_user_desc->base_addr	= (unsigned long)&counter_page[1];
658 	low_user_desc->limit		= 0xfffff;
659 	low_user_desc->seg_32bit	= 1;
660 	low_user_desc->contents		= 0; /* Data, grow-up*/
661 	low_user_desc->read_exec_only	= 0;
662 	low_user_desc->limit_in_pages	= 1;
663 	low_user_desc->seg_not_present	= 0;
664 	low_user_desc->useable		= 0;
665 
666 	if (invoke_set_thread_area() == 0) {
667 		gdt_entry_num = low_user_desc->entry_number;
668 		printf("[NOTE]\tset_thread_area is available; will use GDT index %d\n", gdt_entry_num);
669 	} else {
670 		printf("[NOTE]\tset_thread_area is unavailable\n");
671 	}
672 
673 	low_user_desc_clear = low_user_desc + 1;
674 	low_user_desc_clear->entry_number = gdt_entry_num;
675 	low_user_desc_clear->read_exec_only = 1;
676 	low_user_desc_clear->seg_not_present = 1;
677 }
678 
679 static void test_gdt_invalidation(void)
680 {
681 	if (!gdt_entry_num)
682 		return;	/* 64-bit only system -- we can't use set_thread_area */
683 
684 	unsigned short prev_sel;
685 	unsigned short sel;
686 	unsigned int eax;
687 	const char *result;
688 #ifdef __x86_64__
689 	unsigned long saved_base;
690 	unsigned long new_base;
691 #endif
692 
693 	/* Test DS */
694 	invoke_set_thread_area();
695 	eax = 243;
696 	sel = (gdt_entry_num << 3) | 3;
697 	asm volatile ("movw %%ds, %[prev_sel]\n\t"
698 		      "movw %[sel], %%ds\n\t"
699 #ifdef __i386__
700 		      "pushl %%ebx\n\t"
701 #endif
702 		      "movl %[arg1], %%ebx\n\t"
703 		      "int $0x80\n\t"	/* Should invalidate ds */
704 #ifdef __i386__
705 		      "popl %%ebx\n\t"
706 #endif
707 		      "movw %%ds, %[sel]\n\t"
708 		      "movw %[prev_sel], %%ds"
709 		      : [prev_sel] "=&r" (prev_sel), [sel] "+r" (sel),
710 			"+a" (eax)
711 		      : "m" (low_user_desc_clear),
712 			[arg1] "r" ((unsigned int)(unsigned long)low_user_desc_clear)
713 		      : INT80_CLOBBERS);
714 
715 	if (sel != 0) {
716 		result = "FAIL";
717 		nerrs++;
718 	} else {
719 		result = "OK";
720 	}
721 	printf("[%s]\tInvalidate DS with set_thread_area: new DS = 0x%hx\n",
722 	       result, sel);
723 
724 	/* Test ES */
725 	invoke_set_thread_area();
726 	eax = 243;
727 	sel = (gdt_entry_num << 3) | 3;
728 	asm volatile ("movw %%es, %[prev_sel]\n\t"
729 		      "movw %[sel], %%es\n\t"
730 #ifdef __i386__
731 		      "pushl %%ebx\n\t"
732 #endif
733 		      "movl %[arg1], %%ebx\n\t"
734 		      "int $0x80\n\t"	/* Should invalidate es */
735 #ifdef __i386__
736 		      "popl %%ebx\n\t"
737 #endif
738 		      "movw %%es, %[sel]\n\t"
739 		      "movw %[prev_sel], %%es"
740 		      : [prev_sel] "=&r" (prev_sel), [sel] "+r" (sel),
741 			"+a" (eax)
742 		      : "m" (low_user_desc_clear),
743 			[arg1] "r" ((unsigned int)(unsigned long)low_user_desc_clear)
744 		      : INT80_CLOBBERS);
745 
746 	if (sel != 0) {
747 		result = "FAIL";
748 		nerrs++;
749 	} else {
750 		result = "OK";
751 	}
752 	printf("[%s]\tInvalidate ES with set_thread_area: new ES = 0x%hx\n",
753 	       result, sel);
754 
755 	/* Test FS */
756 	invoke_set_thread_area();
757 	eax = 243;
758 	sel = (gdt_entry_num << 3) | 3;
759 #ifdef __x86_64__
760 	syscall(SYS_arch_prctl, ARCH_GET_FS, &saved_base);
761 #endif
762 	asm volatile ("movw %%fs, %[prev_sel]\n\t"
763 		      "movw %[sel], %%fs\n\t"
764 #ifdef __i386__
765 		      "pushl %%ebx\n\t"
766 #endif
767 		      "movl %[arg1], %%ebx\n\t"
768 		      "int $0x80\n\t"	/* Should invalidate fs */
769 #ifdef __i386__
770 		      "popl %%ebx\n\t"
771 #endif
772 		      "movw %%fs, %[sel]\n\t"
773 		      : [prev_sel] "=&r" (prev_sel), [sel] "+r" (sel),
774 			"+a" (eax)
775 		      : "m" (low_user_desc_clear),
776 			[arg1] "r" ((unsigned int)(unsigned long)low_user_desc_clear)
777 		      : INT80_CLOBBERS);
778 
779 #ifdef __x86_64__
780 	syscall(SYS_arch_prctl, ARCH_GET_FS, &new_base);
781 #endif
782 
783 	/* Restore FS/BASE for glibc */
784 	asm volatile ("movw %[prev_sel], %%fs" : : [prev_sel] "rm" (prev_sel));
785 #ifdef __x86_64__
786 	if (saved_base)
787 		syscall(SYS_arch_prctl, ARCH_SET_FS, saved_base);
788 #endif
789 
790 	if (sel != 0) {
791 		result = "FAIL";
792 		nerrs++;
793 	} else {
794 		result = "OK";
795 	}
796 	printf("[%s]\tInvalidate FS with set_thread_area: new FS = 0x%hx\n",
797 	       result, sel);
798 
799 #ifdef __x86_64__
800 	if (sel == 0 && new_base != 0) {
801 		nerrs++;
802 		printf("[FAIL]\tNew FSBASE was 0x%lx\n", new_base);
803 	} else {
804 		printf("[OK]\tNew FSBASE was zero\n");
805 	}
806 #endif
807 
808 	/* Test GS */
809 	invoke_set_thread_area();
810 	eax = 243;
811 	sel = (gdt_entry_num << 3) | 3;
812 #ifdef __x86_64__
813 	syscall(SYS_arch_prctl, ARCH_GET_GS, &saved_base);
814 #endif
815 	asm volatile ("movw %%gs, %[prev_sel]\n\t"
816 		      "movw %[sel], %%gs\n\t"
817 #ifdef __i386__
818 		      "pushl %%ebx\n\t"
819 #endif
820 		      "movl %[arg1], %%ebx\n\t"
821 		      "int $0x80\n\t"	/* Should invalidate gs */
822 #ifdef __i386__
823 		      "popl %%ebx\n\t"
824 #endif
825 		      "movw %%gs, %[sel]\n\t"
826 		      : [prev_sel] "=&r" (prev_sel), [sel] "+r" (sel),
827 			"+a" (eax)
828 		      : "m" (low_user_desc_clear),
829 			[arg1] "r" ((unsigned int)(unsigned long)low_user_desc_clear)
830 		      : INT80_CLOBBERS);
831 
832 #ifdef __x86_64__
833 	syscall(SYS_arch_prctl, ARCH_GET_GS, &new_base);
834 #endif
835 
836 	/* Restore GS/BASE for glibc */
837 	asm volatile ("movw %[prev_sel], %%gs" : : [prev_sel] "rm" (prev_sel));
838 #ifdef __x86_64__
839 	if (saved_base)
840 		syscall(SYS_arch_prctl, ARCH_SET_GS, saved_base);
841 #endif
842 
843 	if (sel != 0) {
844 		result = "FAIL";
845 		nerrs++;
846 	} else {
847 		result = "OK";
848 	}
849 	printf("[%s]\tInvalidate GS with set_thread_area: new GS = 0x%hx\n",
850 	       result, sel);
851 
852 #ifdef __x86_64__
853 	if (sel == 0 && new_base != 0) {
854 		nerrs++;
855 		printf("[FAIL]\tNew GSBASE was 0x%lx\n", new_base);
856 	} else {
857 		printf("[OK]\tNew GSBASE was zero\n");
858 	}
859 #endif
860 }
861 
862 int main(int argc, char **argv)
863 {
864 	if (argc == 1 && !strcmp(argv[0], "ldt_gdt_test_exec"))
865 		return finish_exec_test();
866 
867 	setup_counter_page();
868 	setup_low_user_desc();
869 
870 	do_simple_tests();
871 
872 	do_multicpu_tests();
873 
874 	do_exec_test();
875 
876 	test_gdt_invalidation();
877 
878 	return nerrs ? 1 : 0;
879 }
880