License cleanup: add SPDX GPL-2.0 license identifier to files with no license
[linux-2.6-block.git] / tools / testing / selftests / x86 / ldt_gdt.c
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 }