0001
0002
0003
0004
0005
0006
0007 #define _GNU_SOURCE
0008 #include <err.h>
0009 #include <stdio.h>
0010 #include <stdint.h>
0011 #include <signal.h>
0012 #include <setjmp.h>
0013 #include <stdlib.h>
0014 #include <string.h>
0015 #include <errno.h>
0016 #include <unistd.h>
0017 #include <sys/syscall.h>
0018 #include <asm/ldt.h>
0019 #include <sys/types.h>
0020 #include <sys/wait.h>
0021 #include <stdbool.h>
0022 #include <pthread.h>
0023 #include <sched.h>
0024 #include <linux/futex.h>
0025 #include <sys/mman.h>
0026 #include <asm/prctl.h>
0027 #include <sys/prctl.h>
0028
0029 #define AR_ACCESSED (1<<8)
0030
0031 #define AR_TYPE_RODATA (0 * (1<<9))
0032 #define AR_TYPE_RWDATA (1 * (1<<9))
0033 #define AR_TYPE_RODATA_EXPDOWN (2 * (1<<9))
0034 #define AR_TYPE_RWDATA_EXPDOWN (3 * (1<<9))
0035 #define AR_TYPE_XOCODE (4 * (1<<9))
0036 #define AR_TYPE_XRCODE (5 * (1<<9))
0037 #define AR_TYPE_XOCODE_CONF (6 * (1<<9))
0038 #define AR_TYPE_XRCODE_CONF (7 * (1<<9))
0039
0040 #define AR_DPL3 (3 * (1<<13))
0041
0042 #define AR_S (1 << 12)
0043 #define AR_P (1 << 15)
0044 #define AR_AVL (1 << 20)
0045 #define AR_L (1 << 21)
0046 #define AR_DB (1 << 22)
0047 #define AR_G (1 << 23)
0048
0049 #ifdef __x86_64__
0050 # define INT80_CLOBBERS "r8", "r9", "r10", "r11"
0051 #else
0052 # define INT80_CLOBBERS
0053 #endif
0054
0055 static int nerrs;
0056
0057
0058 static const unsigned int *counter_page;
0059 static struct user_desc *low_user_desc;
0060 static struct user_desc *low_user_desc_clear;
0061 static int gdt_entry_num;
0062
0063 static void check_invalid_segment(uint16_t index, int ldt)
0064 {
0065 uint32_t has_limit = 0, has_ar = 0, limit, ar;
0066 uint32_t selector = (index << 3) | (ldt << 2) | 3;
0067
0068 asm ("lsl %[selector], %[limit]\n\t"
0069 "jnz 1f\n\t"
0070 "movl $1, %[has_limit]\n\t"
0071 "1:"
0072 : [limit] "=r" (limit), [has_limit] "+rm" (has_limit)
0073 : [selector] "r" (selector));
0074 asm ("larl %[selector], %[ar]\n\t"
0075 "jnz 1f\n\t"
0076 "movl $1, %[has_ar]\n\t"
0077 "1:"
0078 : [ar] "=r" (ar), [has_ar] "+rm" (has_ar)
0079 : [selector] "r" (selector));
0080
0081 if (has_limit || has_ar) {
0082 printf("[FAIL]\t%s entry %hu is valid but should be invalid\n",
0083 (ldt ? "LDT" : "GDT"), index);
0084 nerrs++;
0085 } else {
0086 printf("[OK]\t%s entry %hu is invalid\n",
0087 (ldt ? "LDT" : "GDT"), index);
0088 }
0089 }
0090
0091 static void check_valid_segment(uint16_t index, int ldt,
0092 uint32_t expected_ar, uint32_t expected_limit,
0093 bool verbose)
0094 {
0095 uint32_t has_limit = 0, has_ar = 0, limit, ar;
0096 uint32_t selector = (index << 3) | (ldt << 2) | 3;
0097
0098 asm ("lsl %[selector], %[limit]\n\t"
0099 "jnz 1f\n\t"
0100 "movl $1, %[has_limit]\n\t"
0101 "1:"
0102 : [limit] "=r" (limit), [has_limit] "+rm" (has_limit)
0103 : [selector] "r" (selector));
0104 asm ("larl %[selector], %[ar]\n\t"
0105 "jnz 1f\n\t"
0106 "movl $1, %[has_ar]\n\t"
0107 "1:"
0108 : [ar] "=r" (ar), [has_ar] "+rm" (has_ar)
0109 : [selector] "r" (selector));
0110
0111 if (!has_limit || !has_ar) {
0112 printf("[FAIL]\t%s entry %hu is invalid but should be valid\n",
0113 (ldt ? "LDT" : "GDT"), index);
0114 nerrs++;
0115 return;
0116 }
0117
0118
0119 ar &= ~0xF0000;
0120
0121
0122
0123
0124
0125 if (ar != expected_ar && ar != (expected_ar | AR_ACCESSED)) {
0126 printf("[FAIL]\t%s entry %hu has AR 0x%08X but expected 0x%08X\n",
0127 (ldt ? "LDT" : "GDT"), index, ar, expected_ar);
0128 nerrs++;
0129 } else if (limit != expected_limit) {
0130 printf("[FAIL]\t%s entry %hu has limit 0x%08X but expected 0x%08X\n",
0131 (ldt ? "LDT" : "GDT"), index, limit, expected_limit);
0132 nerrs++;
0133 } else if (verbose) {
0134 printf("[OK]\t%s entry %hu has AR 0x%08X and limit 0x%08X\n",
0135 (ldt ? "LDT" : "GDT"), index, ar, limit);
0136 }
0137 }
0138
0139 static bool install_valid_mode(const struct user_desc *d, uint32_t ar,
0140 bool oldmode, bool ldt)
0141 {
0142 struct user_desc desc = *d;
0143 int ret;
0144
0145 if (!ldt) {
0146 #ifndef __i386__
0147
0148 return false;
0149 #endif
0150 if (!gdt_entry_num)
0151 return false;
0152 desc.entry_number = gdt_entry_num;
0153
0154 ret = syscall(SYS_set_thread_area, &desc);
0155 } else {
0156 ret = syscall(SYS_modify_ldt, oldmode ? 1 : 0x11,
0157 &desc, sizeof(desc));
0158
0159 if (ret < -1)
0160 errno = -ret;
0161
0162 if (ret != 0 && errno == ENOSYS) {
0163 printf("[OK]\tmodify_ldt returned -ENOSYS\n");
0164 return false;
0165 }
0166 }
0167
0168 if (ret == 0) {
0169 uint32_t limit = desc.limit;
0170 if (desc.limit_in_pages)
0171 limit = (limit << 12) + 4095;
0172 check_valid_segment(desc.entry_number, ldt, ar, limit, true);
0173 return true;
0174 } else {
0175 if (desc.seg_32bit) {
0176 printf("[FAIL]\tUnexpected %s failure %d\n",
0177 ldt ? "modify_ldt" : "set_thread_area",
0178 errno);
0179 nerrs++;
0180 return false;
0181 } else {
0182 printf("[OK]\t%s rejected 16 bit segment\n",
0183 ldt ? "modify_ldt" : "set_thread_area");
0184 return false;
0185 }
0186 }
0187 }
0188
0189 static bool install_valid(const struct user_desc *desc, uint32_t ar)
0190 {
0191 bool ret = install_valid_mode(desc, ar, false, true);
0192
0193 if (desc->contents <= 1 && desc->seg_32bit &&
0194 !desc->seg_not_present) {
0195
0196 install_valid_mode(desc, ar, false, false);
0197 }
0198
0199 return ret;
0200 }
0201
0202 static void install_invalid(const struct user_desc *desc, bool oldmode)
0203 {
0204 int ret = syscall(SYS_modify_ldt, oldmode ? 1 : 0x11,
0205 desc, sizeof(*desc));
0206 if (ret < -1)
0207 errno = -ret;
0208 if (ret == 0) {
0209 check_invalid_segment(desc->entry_number, 1);
0210 } else if (errno == ENOSYS) {
0211 printf("[OK]\tmodify_ldt returned -ENOSYS\n");
0212 } else {
0213 if (desc->seg_32bit) {
0214 printf("[FAIL]\tUnexpected modify_ldt failure %d\n",
0215 errno);
0216 nerrs++;
0217 } else {
0218 printf("[OK]\tmodify_ldt rejected 16 bit segment\n");
0219 }
0220 }
0221 }
0222
0223 static int safe_modify_ldt(int func, struct user_desc *ptr,
0224 unsigned long bytecount)
0225 {
0226 int ret = syscall(SYS_modify_ldt, 0x11, ptr, bytecount);
0227 if (ret < -1)
0228 errno = -ret;
0229 return ret;
0230 }
0231
0232 static void fail_install(struct user_desc *desc)
0233 {
0234 if (safe_modify_ldt(0x11, desc, sizeof(*desc)) == 0) {
0235 printf("[FAIL]\tmodify_ldt accepted a bad descriptor\n");
0236 nerrs++;
0237 } else if (errno == ENOSYS) {
0238 printf("[OK]\tmodify_ldt returned -ENOSYS\n");
0239 } else {
0240 printf("[OK]\tmodify_ldt failure %d\n", errno);
0241 }
0242 }
0243
0244 static void do_simple_tests(void)
0245 {
0246 struct user_desc desc = {
0247 .entry_number = 0,
0248 .base_addr = 0,
0249 .limit = 10,
0250 .seg_32bit = 1,
0251 .contents = 2,
0252 .read_exec_only = 0,
0253 .limit_in_pages = 0,
0254 .seg_not_present = 0,
0255 .useable = 0
0256 };
0257 install_valid(&desc, AR_DPL3 | AR_TYPE_XRCODE | AR_S | AR_P | AR_DB);
0258
0259 desc.limit_in_pages = 1;
0260 install_valid(&desc, AR_DPL3 | AR_TYPE_XRCODE |
0261 AR_S | AR_P | AR_DB | AR_G);
0262
0263 check_invalid_segment(1, 1);
0264
0265 desc.entry_number = 2;
0266 install_valid(&desc, AR_DPL3 | AR_TYPE_XRCODE |
0267 AR_S | AR_P | AR_DB | AR_G);
0268
0269 check_invalid_segment(1, 1);
0270
0271 desc.base_addr = 0xf0000000;
0272 install_valid(&desc, AR_DPL3 | AR_TYPE_XRCODE |
0273 AR_S | AR_P | AR_DB | AR_G);
0274
0275 desc.useable = 1;
0276 install_valid(&desc, AR_DPL3 | AR_TYPE_XRCODE |
0277 AR_S | AR_P | AR_DB | AR_G | AR_AVL);
0278
0279 desc.seg_not_present = 1;
0280 install_valid(&desc, AR_DPL3 | AR_TYPE_XRCODE |
0281 AR_S | AR_DB | AR_G | AR_AVL);
0282
0283 desc.seg_32bit = 0;
0284 install_valid(&desc, AR_DPL3 | AR_TYPE_XRCODE |
0285 AR_S | AR_G | AR_AVL);
0286
0287 desc.seg_32bit = 1;
0288 desc.contents = 0;
0289 install_valid(&desc, AR_DPL3 | AR_TYPE_RWDATA |
0290 AR_S | AR_DB | AR_G | AR_AVL);
0291
0292 desc.read_exec_only = 1;
0293 install_valid(&desc, AR_DPL3 | AR_TYPE_RODATA |
0294 AR_S | AR_DB | AR_G | AR_AVL);
0295
0296 desc.contents = 1;
0297 install_valid(&desc, AR_DPL3 | AR_TYPE_RODATA_EXPDOWN |
0298 AR_S | AR_DB | AR_G | AR_AVL);
0299
0300 desc.read_exec_only = 0;
0301 desc.limit_in_pages = 0;
0302 install_valid(&desc, AR_DPL3 | AR_TYPE_RWDATA_EXPDOWN |
0303 AR_S | AR_DB | AR_AVL);
0304
0305 desc.contents = 3;
0306 install_valid(&desc, AR_DPL3 | AR_TYPE_XRCODE_CONF |
0307 AR_S | AR_DB | AR_AVL);
0308
0309 desc.read_exec_only = 1;
0310 install_valid(&desc, AR_DPL3 | AR_TYPE_XOCODE_CONF |
0311 AR_S | AR_DB | AR_AVL);
0312
0313 desc.read_exec_only = 0;
0314 desc.contents = 2;
0315 install_valid(&desc, AR_DPL3 | AR_TYPE_XRCODE |
0316 AR_S | AR_DB | AR_AVL);
0317
0318 desc.read_exec_only = 1;
0319
0320 #ifdef __x86_64__
0321 desc.lm = 1;
0322 install_valid(&desc, AR_DPL3 | AR_TYPE_XOCODE |
0323 AR_S | AR_DB | AR_AVL);
0324 desc.lm = 0;
0325 #endif
0326
0327 bool entry1_okay = install_valid(&desc, AR_DPL3 | AR_TYPE_XOCODE |
0328 AR_S | AR_DB | AR_AVL);
0329
0330 if (entry1_okay) {
0331 printf("[RUN]\tTest fork\n");
0332 pid_t child = fork();
0333 if (child == 0) {
0334 nerrs = 0;
0335 check_valid_segment(desc.entry_number, 1,
0336 AR_DPL3 | AR_TYPE_XOCODE |
0337 AR_S | AR_DB | AR_AVL, desc.limit,
0338 true);
0339 check_invalid_segment(1, 1);
0340 exit(nerrs ? 1 : 0);
0341 } else {
0342 int status;
0343 if (waitpid(child, &status, 0) != child ||
0344 !WIFEXITED(status)) {
0345 printf("[FAIL]\tChild died\n");
0346 nerrs++;
0347 } else if (WEXITSTATUS(status) != 0) {
0348 printf("[FAIL]\tChild failed\n");
0349 nerrs++;
0350 } else {
0351 printf("[OK]\tChild succeeded\n");
0352 }
0353 }
0354
0355 printf("[RUN]\tTest size\n");
0356 int i;
0357 for (i = 0; i < 8192; i++) {
0358 desc.entry_number = i;
0359 desc.limit = i;
0360 if (safe_modify_ldt(0x11, &desc, sizeof(desc)) != 0) {
0361 printf("[FAIL]\tFailed to install entry %d\n", i);
0362 nerrs++;
0363 break;
0364 }
0365 }
0366 for (int j = 0; j < i; j++) {
0367 check_valid_segment(j, 1, AR_DPL3 | AR_TYPE_XOCODE |
0368 AR_S | AR_DB | AR_AVL, j, false);
0369 }
0370 printf("[DONE]\tSize test\n");
0371 } else {
0372 printf("[SKIP]\tSkipping fork and size tests because we have no LDT\n");
0373 }
0374
0375
0376 desc.entry_number = 8192;
0377 fail_install(&desc);
0378
0379
0380 memset(&desc, 0, sizeof(desc));
0381 install_valid(&desc, AR_DPL3 | AR_TYPE_RWDATA | AR_S | AR_P);
0382
0383 desc.seg_not_present = 1;
0384 install_valid(&desc, AR_DPL3 | AR_TYPE_RWDATA | AR_S);
0385
0386 desc.seg_not_present = 0;
0387 desc.read_exec_only = 1;
0388 install_valid(&desc, AR_DPL3 | AR_TYPE_RODATA | AR_S | AR_P);
0389
0390 desc.read_exec_only = 0;
0391 desc.seg_not_present = 1;
0392 install_valid(&desc, AR_DPL3 | AR_TYPE_RWDATA | AR_S);
0393
0394 desc.read_exec_only = 1;
0395 desc.limit = 1;
0396 install_valid(&desc, AR_DPL3 | AR_TYPE_RODATA | AR_S);
0397
0398 desc.limit = 0;
0399 desc.base_addr = 1;
0400 install_valid(&desc, AR_DPL3 | AR_TYPE_RODATA | AR_S);
0401
0402 desc.base_addr = 0;
0403 install_invalid(&desc, false);
0404
0405 desc.seg_not_present = 0;
0406 desc.seg_32bit = 1;
0407 desc.read_exec_only = 0;
0408 desc.limit = 0xfffff;
0409
0410 install_valid(&desc, AR_DPL3 | AR_TYPE_RWDATA | AR_S | AR_P | AR_DB);
0411
0412 desc.limit_in_pages = 1;
0413
0414 install_valid(&desc, AR_DPL3 | AR_TYPE_RWDATA | AR_S | AR_P | AR_DB | AR_G);
0415 desc.read_exec_only = 1;
0416 install_valid(&desc, AR_DPL3 | AR_TYPE_RODATA | AR_S | AR_P | AR_DB | AR_G);
0417 desc.contents = 1;
0418 desc.read_exec_only = 0;
0419 install_valid(&desc, AR_DPL3 | AR_TYPE_RWDATA_EXPDOWN | AR_S | AR_P | AR_DB | AR_G);
0420 desc.read_exec_only = 1;
0421 install_valid(&desc, AR_DPL3 | AR_TYPE_RODATA_EXPDOWN | AR_S | AR_P | AR_DB | AR_G);
0422
0423 desc.limit = 0;
0424 install_invalid(&desc, true);
0425 }
0426
0427
0428
0429
0430
0431
0432
0433 static volatile unsigned int ftx;
0434
0435 static void *threadproc(void *ctx)
0436 {
0437 cpu_set_t cpuset;
0438 CPU_ZERO(&cpuset);
0439 CPU_SET(1, &cpuset);
0440 if (sched_setaffinity(0, sizeof(cpuset), &cpuset) != 0)
0441 err(1, "sched_setaffinity to CPU 1");
0442
0443 while (1) {
0444 syscall(SYS_futex, &ftx, FUTEX_WAIT, 0, NULL, NULL, 0);
0445 while (ftx != 2) {
0446 if (ftx >= 3)
0447 return NULL;
0448 }
0449
0450
0451 const struct user_desc desc = {};
0452 if (syscall(SYS_modify_ldt, 1, &desc, sizeof(desc)) != 0)
0453 err(1, "modify_ldt");
0454
0455
0456 unsigned int x = -2;
0457 asm volatile ("lock xaddl %[x], %[ftx]" :
0458 [x] "+r" (x), [ftx] "+m" (ftx));
0459 if (x != 2)
0460 return NULL;
0461 }
0462 }
0463
0464 #ifdef __i386__
0465
0466 #ifndef SA_RESTORE
0467 #define SA_RESTORER 0x04000000
0468 #endif
0469
0470
0471
0472
0473
0474 struct fake_ksigaction {
0475 void *handler;
0476 unsigned long sa_flags;
0477 void (*sa_restorer)(void);
0478 unsigned char sigset[8];
0479 };
0480
0481 static void fix_sa_restorer(int sig)
0482 {
0483 struct fake_ksigaction ksa;
0484
0485 if (syscall(SYS_rt_sigaction, sig, NULL, &ksa, 8) == 0) {
0486
0487
0488
0489
0490
0491
0492
0493
0494 if (!(ksa.sa_flags & SA_RESTORER) && ksa.sa_restorer) {
0495 ksa.sa_restorer = NULL;
0496 if (syscall(SYS_rt_sigaction, sig, &ksa, NULL,
0497 sizeof(ksa.sigset)) != 0)
0498 err(1, "rt_sigaction");
0499 }
0500 }
0501 }
0502 #else
0503 static void fix_sa_restorer(int sig)
0504 {
0505
0506 }
0507 #endif
0508
0509 static void sethandler(int sig, void (*handler)(int, siginfo_t *, void *),
0510 int flags)
0511 {
0512 struct sigaction sa;
0513 memset(&sa, 0, sizeof(sa));
0514 sa.sa_sigaction = handler;
0515 sa.sa_flags = SA_SIGINFO | flags;
0516 sigemptyset(&sa.sa_mask);
0517 if (sigaction(sig, &sa, 0))
0518 err(1, "sigaction");
0519
0520 fix_sa_restorer(sig);
0521 }
0522
0523 static jmp_buf jmpbuf;
0524
0525 static void sigsegv(int sig, siginfo_t *info, void *ctx_void)
0526 {
0527 siglongjmp(jmpbuf, 1);
0528 }
0529
0530 static void do_multicpu_tests(void)
0531 {
0532 cpu_set_t cpuset;
0533 pthread_t thread;
0534 int failures = 0, iters = 5, i;
0535 unsigned short orig_ss;
0536
0537 CPU_ZERO(&cpuset);
0538 CPU_SET(1, &cpuset);
0539 if (sched_setaffinity(0, sizeof(cpuset), &cpuset) != 0) {
0540 printf("[SKIP]\tCannot set affinity to CPU 1\n");
0541 return;
0542 }
0543
0544 CPU_ZERO(&cpuset);
0545 CPU_SET(0, &cpuset);
0546 if (sched_setaffinity(0, sizeof(cpuset), &cpuset) != 0) {
0547 printf("[SKIP]\tCannot set affinity to CPU 0\n");
0548 return;
0549 }
0550
0551 sethandler(SIGSEGV, sigsegv, 0);
0552 #ifdef __i386__
0553
0554 sethandler(SIGILL, sigsegv, 0);
0555 #endif
0556
0557 printf("[RUN]\tCross-CPU LDT invalidation\n");
0558
0559 if (pthread_create(&thread, 0, threadproc, 0) != 0)
0560 err(1, "pthread_create");
0561
0562 asm volatile ("mov %%ss, %0" : "=rm" (orig_ss));
0563
0564 for (i = 0; i < 5; i++) {
0565 if (sigsetjmp(jmpbuf, 1) != 0)
0566 continue;
0567
0568
0569 while (ftx != 0)
0570 ;
0571
0572 struct user_desc desc = {
0573 .entry_number = 0,
0574 .base_addr = 0,
0575 .limit = 0xfffff,
0576 .seg_32bit = 1,
0577 .contents = 0,
0578 .read_exec_only = 0,
0579 .limit_in_pages = 1,
0580 .seg_not_present = 0,
0581 .useable = 0
0582 };
0583
0584 if (safe_modify_ldt(0x11, &desc, sizeof(desc)) != 0) {
0585 if (errno != ENOSYS)
0586 err(1, "modify_ldt");
0587 printf("[SKIP]\tmodify_ldt unavailable\n");
0588 break;
0589 }
0590
0591
0592 ftx = 1;
0593 syscall(SYS_futex, &ftx, FUTEX_WAKE, 0, NULL, NULL, 0);
0594
0595 asm volatile ("mov %0, %%ss" : : "r" (0x7));
0596
0597
0598 ftx = 2;
0599
0600 while (ftx != 0)
0601 ;
0602
0603
0604
0605
0606
0607
0608 failures++;
0609 asm volatile ("mov %0, %%ss" : : "rm" (orig_ss));
0610 }
0611
0612 ftx = 100;
0613 syscall(SYS_futex, &ftx, FUTEX_WAKE, 0, NULL, NULL, 0);
0614
0615 if (pthread_join(thread, NULL) != 0)
0616 err(1, "pthread_join");
0617
0618 if (failures) {
0619 printf("[FAIL]\t%d of %d iterations failed\n", failures, iters);
0620 nerrs++;
0621 } else {
0622 printf("[OK]\tAll %d iterations succeeded\n", iters);
0623 }
0624 }
0625
0626 static int finish_exec_test(void)
0627 {
0628
0629
0630
0631
0632 check_invalid_segment(0, 1);
0633
0634 return nerrs ? 1 : 0;
0635 }
0636
0637 static void do_exec_test(void)
0638 {
0639 printf("[RUN]\tTest exec\n");
0640
0641 struct user_desc desc = {
0642 .entry_number = 0,
0643 .base_addr = 0,
0644 .limit = 42,
0645 .seg_32bit = 1,
0646 .contents = 2,
0647 .read_exec_only = 0,
0648 .limit_in_pages = 0,
0649 .seg_not_present = 0,
0650 .useable = 0
0651 };
0652 install_valid(&desc, AR_DPL3 | AR_TYPE_XRCODE | AR_S | AR_P | AR_DB);
0653
0654 pid_t child = fork();
0655 if (child == 0) {
0656 execl("/proc/self/exe", "ldt_gdt_test_exec", NULL);
0657 printf("[FAIL]\tCould not exec self\n");
0658 exit(1);
0659 } else {
0660 int status;
0661 if (waitpid(child, &status, 0) != child ||
0662 !WIFEXITED(status)) {
0663 printf("[FAIL]\tChild died\n");
0664 nerrs++;
0665 } else if (WEXITSTATUS(status) != 0) {
0666 printf("[FAIL]\tChild failed\n");
0667 nerrs++;
0668 } else {
0669 printf("[OK]\tChild succeeded\n");
0670 }
0671 }
0672 }
0673
0674 static void setup_counter_page(void)
0675 {
0676 unsigned int *page = mmap(NULL, 4096, PROT_READ | PROT_WRITE,
0677 MAP_ANONYMOUS | MAP_PRIVATE | MAP_32BIT, -1, 0);
0678 if (page == MAP_FAILED)
0679 err(1, "mmap");
0680
0681 for (int i = 0; i < 1024; i++)
0682 page[i] = i;
0683 counter_page = page;
0684 }
0685
0686 static int invoke_set_thread_area(void)
0687 {
0688 int ret;
0689 asm volatile ("int $0x80"
0690 : "=a" (ret), "+m" (low_user_desc) :
0691 "a" (243), "b" (low_user_desc)
0692 : INT80_CLOBBERS);
0693 return ret;
0694 }
0695
0696 static void setup_low_user_desc(void)
0697 {
0698 low_user_desc = mmap(NULL, 2 * sizeof(struct user_desc),
0699 PROT_READ | PROT_WRITE,
0700 MAP_ANONYMOUS | MAP_PRIVATE | MAP_32BIT, -1, 0);
0701 if (low_user_desc == MAP_FAILED)
0702 err(1, "mmap");
0703
0704 low_user_desc->entry_number = -1;
0705 low_user_desc->base_addr = (unsigned long)&counter_page[1];
0706 low_user_desc->limit = 0xfffff;
0707 low_user_desc->seg_32bit = 1;
0708 low_user_desc->contents = 0;
0709 low_user_desc->read_exec_only = 0;
0710 low_user_desc->limit_in_pages = 1;
0711 low_user_desc->seg_not_present = 0;
0712 low_user_desc->useable = 0;
0713
0714 if (invoke_set_thread_area() == 0) {
0715 gdt_entry_num = low_user_desc->entry_number;
0716 printf("[NOTE]\tset_thread_area is available; will use GDT index %d\n", gdt_entry_num);
0717 } else {
0718 printf("[NOTE]\tset_thread_area is unavailable\n");
0719 }
0720
0721 low_user_desc_clear = low_user_desc + 1;
0722 low_user_desc_clear->entry_number = gdt_entry_num;
0723 low_user_desc_clear->read_exec_only = 1;
0724 low_user_desc_clear->seg_not_present = 1;
0725 }
0726
0727 static void test_gdt_invalidation(void)
0728 {
0729 if (!gdt_entry_num)
0730 return;
0731
0732 unsigned short prev_sel;
0733 unsigned short sel;
0734 unsigned int eax;
0735 const char *result;
0736 #ifdef __x86_64__
0737 unsigned long saved_base;
0738 unsigned long new_base;
0739 #endif
0740
0741
0742 invoke_set_thread_area();
0743 eax = 243;
0744 sel = (gdt_entry_num << 3) | 3;
0745 asm volatile ("movw %%ds, %[prev_sel]\n\t"
0746 "movw %[sel], %%ds\n\t"
0747 #ifdef __i386__
0748 "pushl %%ebx\n\t"
0749 #endif
0750 "movl %[arg1], %%ebx\n\t"
0751 "int $0x80\n\t"
0752 #ifdef __i386__
0753 "popl %%ebx\n\t"
0754 #endif
0755 "movw %%ds, %[sel]\n\t"
0756 "movw %[prev_sel], %%ds"
0757 : [prev_sel] "=&r" (prev_sel), [sel] "+r" (sel),
0758 "+a" (eax)
0759 : "m" (low_user_desc_clear),
0760 [arg1] "r" ((unsigned int)(unsigned long)low_user_desc_clear)
0761 : INT80_CLOBBERS);
0762
0763 if (sel != 0) {
0764 result = "FAIL";
0765 nerrs++;
0766 } else {
0767 result = "OK";
0768 }
0769 printf("[%s]\tInvalidate DS with set_thread_area: new DS = 0x%hx\n",
0770 result, sel);
0771
0772
0773 invoke_set_thread_area();
0774 eax = 243;
0775 sel = (gdt_entry_num << 3) | 3;
0776 asm volatile ("movw %%es, %[prev_sel]\n\t"
0777 "movw %[sel], %%es\n\t"
0778 #ifdef __i386__
0779 "pushl %%ebx\n\t"
0780 #endif
0781 "movl %[arg1], %%ebx\n\t"
0782 "int $0x80\n\t"
0783 #ifdef __i386__
0784 "popl %%ebx\n\t"
0785 #endif
0786 "movw %%es, %[sel]\n\t"
0787 "movw %[prev_sel], %%es"
0788 : [prev_sel] "=&r" (prev_sel), [sel] "+r" (sel),
0789 "+a" (eax)
0790 : "m" (low_user_desc_clear),
0791 [arg1] "r" ((unsigned int)(unsigned long)low_user_desc_clear)
0792 : INT80_CLOBBERS);
0793
0794 if (sel != 0) {
0795 result = "FAIL";
0796 nerrs++;
0797 } else {
0798 result = "OK";
0799 }
0800 printf("[%s]\tInvalidate ES with set_thread_area: new ES = 0x%hx\n",
0801 result, sel);
0802
0803
0804 invoke_set_thread_area();
0805 eax = 243;
0806 sel = (gdt_entry_num << 3) | 3;
0807 #ifdef __x86_64__
0808 syscall(SYS_arch_prctl, ARCH_GET_FS, &saved_base);
0809 #endif
0810 asm volatile ("movw %%fs, %[prev_sel]\n\t"
0811 "movw %[sel], %%fs\n\t"
0812 #ifdef __i386__
0813 "pushl %%ebx\n\t"
0814 #endif
0815 "movl %[arg1], %%ebx\n\t"
0816 "int $0x80\n\t"
0817 #ifdef __i386__
0818 "popl %%ebx\n\t"
0819 #endif
0820 "movw %%fs, %[sel]\n\t"
0821 : [prev_sel] "=&r" (prev_sel), [sel] "+r" (sel),
0822 "+a" (eax)
0823 : "m" (low_user_desc_clear),
0824 [arg1] "r" ((unsigned int)(unsigned long)low_user_desc_clear)
0825 : INT80_CLOBBERS);
0826
0827 #ifdef __x86_64__
0828 syscall(SYS_arch_prctl, ARCH_GET_FS, &new_base);
0829 #endif
0830
0831
0832 asm volatile ("movw %[prev_sel], %%fs" : : [prev_sel] "rm" (prev_sel));
0833 #ifdef __x86_64__
0834 if (saved_base)
0835 syscall(SYS_arch_prctl, ARCH_SET_FS, saved_base);
0836 #endif
0837
0838 if (sel != 0) {
0839 result = "FAIL";
0840 nerrs++;
0841 } else {
0842 result = "OK";
0843 }
0844 printf("[%s]\tInvalidate FS with set_thread_area: new FS = 0x%hx\n",
0845 result, sel);
0846
0847 #ifdef __x86_64__
0848 if (sel == 0 && new_base != 0) {
0849 nerrs++;
0850 printf("[FAIL]\tNew FSBASE was 0x%lx\n", new_base);
0851 } else {
0852 printf("[OK]\tNew FSBASE was zero\n");
0853 }
0854 #endif
0855
0856
0857 invoke_set_thread_area();
0858 eax = 243;
0859 sel = (gdt_entry_num << 3) | 3;
0860 #ifdef __x86_64__
0861 syscall(SYS_arch_prctl, ARCH_GET_GS, &saved_base);
0862 #endif
0863 asm volatile ("movw %%gs, %[prev_sel]\n\t"
0864 "movw %[sel], %%gs\n\t"
0865 #ifdef __i386__
0866 "pushl %%ebx\n\t"
0867 #endif
0868 "movl %[arg1], %%ebx\n\t"
0869 "int $0x80\n\t"
0870 #ifdef __i386__
0871 "popl %%ebx\n\t"
0872 #endif
0873 "movw %%gs, %[sel]\n\t"
0874 : [prev_sel] "=&r" (prev_sel), [sel] "+r" (sel),
0875 "+a" (eax)
0876 : "m" (low_user_desc_clear),
0877 [arg1] "r" ((unsigned int)(unsigned long)low_user_desc_clear)
0878 : INT80_CLOBBERS);
0879
0880 #ifdef __x86_64__
0881 syscall(SYS_arch_prctl, ARCH_GET_GS, &new_base);
0882 #endif
0883
0884
0885 asm volatile ("movw %[prev_sel], %%gs" : : [prev_sel] "rm" (prev_sel));
0886 #ifdef __x86_64__
0887 if (saved_base)
0888 syscall(SYS_arch_prctl, ARCH_SET_GS, saved_base);
0889 #endif
0890
0891 if (sel != 0) {
0892 result = "FAIL";
0893 nerrs++;
0894 } else {
0895 result = "OK";
0896 }
0897 printf("[%s]\tInvalidate GS with set_thread_area: new GS = 0x%hx\n",
0898 result, sel);
0899
0900 #ifdef __x86_64__
0901 if (sel == 0 && new_base != 0) {
0902 nerrs++;
0903 printf("[FAIL]\tNew GSBASE was 0x%lx\n", new_base);
0904 } else {
0905 printf("[OK]\tNew GSBASE was zero\n");
0906 }
0907 #endif
0908 }
0909
0910 int main(int argc, char **argv)
0911 {
0912 if (argc == 1 && !strcmp(argv[0], "ldt_gdt_test_exec"))
0913 return finish_exec_test();
0914
0915 setup_counter_page();
0916 setup_low_user_desc();
0917
0918 do_simple_tests();
0919
0920 do_multicpu_tests();
0921
0922 do_exec_test();
0923
0924 test_gdt_invalidation();
0925
0926 return nerrs ? 1 : 0;
0927 }