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