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