root/tools/testing/selftests/x86/ldt_gdt.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. check_invalid_segment
  2. check_valid_segment
  3. install_valid_mode
  4. install_valid
  5. install_invalid
  6. safe_modify_ldt
  7. fail_install
  8. do_simple_tests
  9. threadproc
  10. fix_sa_restorer
  11. fix_sa_restorer
  12. sethandler
  13. sigsegv
  14. do_multicpu_tests
  15. finish_exec_test
  16. do_exec_test
  17. setup_counter_page
  18. invoke_set_thread_area
  19. setup_low_user_desc
  20. test_gdt_invalidation
  21. main

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

/* [<][>][^][v][top][bottom][index][help] */