ldt_gdt.c 21 KB

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