mpxrt.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516
  1. /* mpxrt.c -*-C++-*-
  2. *
  3. *************************************************************************
  4. *
  5. * @copyright
  6. * Copyright (C) 2014, Intel Corporation
  7. * All rights reserved.
  8. *
  9. * @copyright
  10. * Redistribution and use in source and binary forms, with or without
  11. * modification, are permitted provided that the following conditions
  12. * are met:
  13. *
  14. * * Redistributions of source code must retain the above copyright
  15. * notice, this list of conditions and the following disclaimer.
  16. * * Redistributions in binary form must reproduce the above copyright
  17. * notice, this list of conditions and the following disclaimer in
  18. * the documentation and/or other materials provided with the
  19. * distribution.
  20. * * Neither the name of Intel Corporation nor the names of its
  21. * contributors may be used to endorse or promote products derived
  22. * from this software without specific prior written permission.
  23. *
  24. * @copyright
  25. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  26. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  27. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  28. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  29. * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  30. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  31. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  32. * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  33. * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  34. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
  35. * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  36. * POSSIBILITY OF SUCH DAMAGE.
  37. *
  38. **************************************************************************/
  39. #define __STDC_FORMAT_MACROS
  40. #include "config.h"
  41. #include <inttypes.h>
  42. #include <stdio.h>
  43. #include <string.h>
  44. #include <stdint.h>
  45. #include <stdbool.h>
  46. #include <signal.h>
  47. #include <assert.h>
  48. #include <stdlib.h>
  49. #include <sys/mman.h>
  50. #include <sys/prctl.h>
  51. #include <cpuid.h>
  52. #include "mpxrt-utils.h"
  53. #ifdef __i386__
  54. /* i386 directory size is 4MB */
  55. #define NUM_L1_BITS 20
  56. #define REG_IP_IDX REG_EIP
  57. #define REX_PREFIX
  58. #define XSAVE_OFFSET_IN_FPMEM sizeof (struct _libc_fpstate)
  59. #else /* __i386__ */
  60. /* x86_64 directory size is 2GB */
  61. #define NUM_L1_BITS 28
  62. #define REG_IP_IDX REG_RIP
  63. #define REX_PREFIX "0x48, "
  64. #define XSAVE_OFFSET_IN_FPMEM 0
  65. #endif /* !__i386__ */
  66. #define MPX_ENABLE_BIT_NO 0
  67. #define BNDPRESERVE_BIT_NO 1
  68. const size_t MPX_L1_SIZE = (1UL << NUM_L1_BITS) * sizeof (void *);
  69. struct xsave_hdr_struct
  70. {
  71. uint64_t xstate_bv;
  72. uint64_t reserved1[2];
  73. uint64_t reserved2[5];
  74. } __attribute__ ((packed));
  75. struct bndregs_struct
  76. {
  77. uint64_t bndregs[8];
  78. } __attribute__ ((packed));
  79. struct bndcsr_struct {
  80. uint64_t cfg_reg_u;
  81. uint64_t status_reg;
  82. } __attribute__((packed));
  83. struct xsave_struct
  84. {
  85. uint8_t fpu_sse[512];
  86. struct xsave_hdr_struct xsave_hdr;
  87. uint8_t ymm[256];
  88. uint8_t lwp[128];
  89. struct bndregs_struct bndregs;
  90. struct bndcsr_struct bndcsr;
  91. } __attribute__ ((packed));
  92. /* Following vars are initialized at process startup only
  93. and thus are considered to be thread safe. */
  94. static void *l1base = NULL;
  95. static int bndpreserve;
  96. static int enable = 1;
  97. /* Var holding number of occured BRs. It is modified from
  98. signal handler only and thus it should be thread safe. */
  99. static uint64_t num_bnd_chk = 0;
  100. static inline void
  101. xrstor_state (struct xsave_struct *fx, uint64_t mask)
  102. {
  103. uint32_t lmask = mask;
  104. uint32_t hmask = mask >> 32;
  105. asm volatile (".byte " REX_PREFIX "0x0f,0xae,0x2f\n\t"
  106. : : "D" (fx), "m" (*fx), "a" (lmask), "d" (hmask)
  107. : "memory");
  108. }
  109. static inline void
  110. xsave_state (struct xsave_struct *fx, uint64_t mask)
  111. {
  112. uint32_t lmask = mask;
  113. uint32_t hmask = mask >> 32;
  114. asm volatile (".byte " REX_PREFIX "0x0f,0xae,0x27\n\t"
  115. : : "D" (fx), "m" (*fx), "a" (lmask), "d" (hmask)
  116. : "memory");
  117. }
  118. static inline uint64_t
  119. xgetbv (uint32_t index)
  120. {
  121. uint32_t eax, edx;
  122. asm volatile (".byte 0x0f,0x01,0xd0" /* xgetbv */
  123. : "=a" (eax), "=d" (edx)
  124. : "c" (index));
  125. return eax + ((uint64_t)edx << 32);
  126. }
  127. static uint64_t
  128. read_mpx_status_sig (ucontext_t *uctxt)
  129. {
  130. uint8_t __attribute__ ((__aligned__ (64))) buffer[4096];
  131. struct xsave_struct *xsave_buf = (struct xsave_struct *)buffer;
  132. memset (buffer, 0, sizeof (buffer));
  133. memcpy (buffer,
  134. (uint8_t *)uctxt->uc_mcontext.fpregs + XSAVE_OFFSET_IN_FPMEM,
  135. sizeof (struct xsave_struct));
  136. return xsave_buf->bndcsr.status_reg;
  137. }
  138. static uint8_t *
  139. get_next_inst_ip (uint8_t *addr)
  140. {
  141. uint8_t *ip = addr;
  142. uint8_t sib;
  143. /* Determine the prefix. */
  144. switch (*ip)
  145. {
  146. case 0xf2:
  147. case 0xf3:
  148. case 0x66:
  149. ip++;
  150. break;
  151. }
  152. /* Look for rex prefix. */
  153. if ((*ip & 0x40) == 0x40)
  154. ip++;
  155. /* Make sure we have a MPX instruction. */
  156. if (*ip++ != 0x0f)
  157. return addr;
  158. /* Skip the op code byte. */
  159. ip++;
  160. /* Get the moderm byte. */
  161. uint8_t modrm = *ip++;
  162. /* Break it down into parts. */
  163. uint8_t rm = modrm & 7;
  164. uint8_t mod = (modrm >> 6);
  165. /* Init the parts of the address mode. */
  166. uint8_t base = 8;
  167. /* Is it a mem mode? */
  168. if (mod != 3)
  169. {
  170. /* Look for scaled indexed addressing. */
  171. if (rm == 4)
  172. {
  173. /* SIB addressing. */
  174. sib = *ip++;
  175. base = sib & 7;
  176. switch (mod)
  177. {
  178. case 0:
  179. if (base == 5)
  180. ip += 4;
  181. break;
  182. case 1:
  183. ip++;
  184. break;
  185. case 2:
  186. ip += 4;
  187. break;
  188. }
  189. }
  190. else
  191. {
  192. /* MODRM addressing. */
  193. switch (mod)
  194. {
  195. case 0:
  196. if (rm == 5)
  197. /* DISP32 addressing, no base. */
  198. ip += 4;
  199. break;
  200. case 1:
  201. ip++;
  202. break;
  203. case 2:
  204. ip += 4;
  205. break;
  206. }
  207. }
  208. }
  209. return ip;
  210. }
  211. static void
  212. handler (int sig __attribute__ ((unused)),
  213. siginfo_t *info __attribute__ ((unused)),
  214. void *vucontext,
  215. struct xsave_struct *buf __attribute__ ((unused)))
  216. {
  217. ucontext_t* uctxt;
  218. greg_t trapno;
  219. greg_t ip;
  220. uctxt = vucontext;
  221. trapno = uctxt->uc_mcontext.gregs[REG_TRAPNO];
  222. ip = uctxt->uc_mcontext.gregs[REG_IP_IDX];
  223. if (trapno == 5)
  224. {
  225. uint64_t status = read_mpx_status_sig (uctxt);
  226. uint64_t br_reason = status & 0x3;
  227. __mpxrt_write (VERB_BR, "Saw a #BR! status ");
  228. __mpxrt_write_uint (VERB_BR, status, 10);
  229. __mpxrt_write (VERB_BR, " at 0x");
  230. __mpxrt_write_uint (VERB_BR, ip, 16);
  231. __mpxrt_write (VERB_BR, "\n");
  232. switch (br_reason)
  233. {
  234. case 1: /* traditional BR */
  235. num_bnd_chk++;
  236. uctxt->uc_mcontext.gregs[REG_IP_IDX] =
  237. (greg_t)get_next_inst_ip ((uint8_t *)ip);
  238. if (__mpxrt_mode () == MPX_RT_STOP)
  239. exit (255);
  240. return;
  241. default:
  242. __mpxrt_write (VERB_BR, "Unexpected status with bound exception: ");
  243. __mpxrt_write_uint (VERB_BR, status, 10);
  244. __mpxrt_write (VERB_BR, "\n");
  245. break;
  246. }
  247. }
  248. else if (trapno == 14)
  249. {
  250. __mpxrt_write (VERB_ERROR, "In signal handler, trapno = ");
  251. __mpxrt_write_uint (VERB_ERROR, trapno, 10);
  252. __mpxrt_write (VERB_ERROR, ", ip = 0x");
  253. __mpxrt_write_uint (VERB_ERROR, ip, 16);
  254. __mpxrt_write (VERB_BR, "\n");
  255. exit (255);
  256. }
  257. else
  258. {
  259. __mpxrt_write (VERB_ERROR, "Unexpected trap ");
  260. __mpxrt_write_uint (VERB_ERROR, trapno, 10);
  261. __mpxrt_write (VERB_ERROR, "! at 0x");
  262. __mpxrt_write_uint (VERB_ERROR, ip, 16);
  263. __mpxrt_write (VERB_BR, "\n");
  264. exit (255);
  265. }
  266. }
  267. /* Using wrapper to the real handler in order to save the bnd regs
  268. using xsave before any unprefixed call. an unprefixed call to
  269. __i686.get_pc_thunk.bx is added by the linker in 32bit at the
  270. beginning of handler function since there are references to
  271. global variables. */
  272. static void
  273. handler_wrap (int signum, siginfo_t* si, void* vucontext)
  274. {
  275. /* Since the OS currently not handling chkptr regs.
  276. We need to store them for later use. They might be
  277. init due to unprefixed call,Jcc,ret. avoiding calling
  278. function since the function will be unprefixed as well. */
  279. uint8_t __attribute__ ((__aligned__ (64))) buffer[4096];
  280. struct xsave_struct *xsave_buf = (struct xsave_struct *)buffer;
  281. uint64_t mask = 0x18;
  282. uint32_t lmask = mask;
  283. uint32_t hmask = mask >> 32;
  284. asm volatile (".byte " REX_PREFIX "0x0f,0xae,0x27\n\t"
  285. : : "D" (xsave_buf), "m" (*xsave_buf),
  286. "a" (lmask), "d" (hmask)
  287. : "memory");
  288. handler (signum, si, vucontext, xsave_buf);
  289. }
  290. static bool
  291. check_mpx_support (void)
  292. {
  293. unsigned int eax, ebx, ecx, edx;
  294. unsigned int max_level = __get_cpuid_max (0, NULL);
  295. if (max_level < 13)
  296. {
  297. __mpxrt_print (VERB_DEBUG, "No required CPUID level support.\n");
  298. return false;
  299. }
  300. __cpuid_count (0, 0, eax, ebx, ecx, edx);
  301. if (!(ecx & bit_XSAVE))
  302. {
  303. __mpxrt_print (VERB_DEBUG, "No XSAVE support.\n");
  304. return false;
  305. }
  306. if (!(ecx & bit_OSXSAVE))
  307. {
  308. __mpxrt_print (VERB_DEBUG, "No OSXSAVE support.\n");
  309. return false;
  310. }
  311. __cpuid_count (7, 0, eax, ebx, ecx, edx);
  312. if (!(ebx & bit_MPX))
  313. {
  314. __mpxrt_print (VERB_DEBUG, "No MPX support.\n");
  315. return false;
  316. }
  317. __cpuid_count (13, 0, eax, ebx, ecx, edx);
  318. if (!(eax & bit_BNDREGS))
  319. {
  320. __mpxrt_print (VERB_DEBUG, "No BNDREGS support.\n");
  321. return false;
  322. }
  323. if (!(eax & bit_BNDCSR))
  324. {
  325. __mpxrt_print (VERB_DEBUG, "No BNDCSR support.\n");
  326. return false;
  327. }
  328. return true;
  329. }
  330. static void
  331. enable_mpx (void)
  332. {
  333. uint8_t __attribute__ ((__aligned__ (64))) buffer[4096];
  334. struct xsave_struct *xsave_buf = (struct xsave_struct *)buffer;
  335. memset (buffer, 0, sizeof (buffer));
  336. xrstor_state (xsave_buf, 0x18);
  337. __mpxrt_print (VERB_DEBUG, "Initalizing MPX...\n");
  338. __mpxrt_print (VERB_DEBUG, " Enable bit: %d\n", enable);
  339. __mpxrt_print (VERB_DEBUG, " BNDPRESERVE bit: %d\n", bndpreserve);
  340. /* Enable MPX. */
  341. xsave_buf->xsave_hdr.xstate_bv = 0x10;
  342. xsave_buf->bndcsr.cfg_reg_u = (unsigned long)l1base;
  343. xsave_buf->bndcsr.cfg_reg_u |= enable << MPX_ENABLE_BIT_NO;
  344. xsave_buf->bndcsr.cfg_reg_u |= bndpreserve << BNDPRESERVE_BIT_NO;
  345. xsave_buf->bndcsr.status_reg = 0;
  346. xrstor_state (xsave_buf, 0x10);
  347. }
  348. static void
  349. disable_mpx (void)
  350. {
  351. uint8_t __attribute__ ((__aligned__ (64))) buffer[4096];
  352. struct xsave_struct *xsave_buf = (struct xsave_struct *)buffer;
  353. memset(buffer, 0, sizeof(buffer));
  354. xrstor_state(xsave_buf, 0x18);
  355. /* Disable MPX. */
  356. xsave_buf->xsave_hdr.xstate_bv = 0x10;
  357. xsave_buf->bndcsr.cfg_reg_u = 0;
  358. xsave_buf->bndcsr.status_reg = 0;
  359. xrstor_state(xsave_buf, 0x10);
  360. }
  361. static bool
  362. process_specific_init (void)
  363. {
  364. if (!check_mpx_support ())
  365. return false;
  366. l1base = mmap (NULL, MPX_L1_SIZE, PROT_READ | PROT_WRITE,
  367. MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
  368. if (l1base == MAP_FAILED)
  369. {
  370. perror ("mmap");
  371. exit (EXIT_FAILURE);
  372. }
  373. enable_mpx ();
  374. if (prctl (43, 0, 0, 0, 0))
  375. {
  376. __mpxrt_print (VERB_ERROR, "No MPX support\n");
  377. disable_mpx ();
  378. return false;
  379. }
  380. return true;
  381. }
  382. static bool
  383. process_specific_finish (void)
  384. {
  385. if (!check_mpx_support ())
  386. return false;
  387. if (prctl (44, 0, 0, 0, 0))
  388. {
  389. __mpxrt_print (VERB_ERROR, "No MPX support\n");
  390. return false;
  391. }
  392. munmap (l1base, MPX_L1_SIZE);
  393. return true;
  394. }
  395. static void
  396. setup_handler (void)
  397. {
  398. int r,rs;
  399. struct sigaction newact;
  400. /* #BR is mapped to sigsegv */
  401. int signum = SIGSEGV;
  402. newact.sa_handler = 0;
  403. newact.sa_sigaction = handler_wrap;
  404. /* sigset_t - signals to block while in the handler
  405. get the old signal mask. */
  406. rs = sigprocmask (SIG_SETMASK, 0, &newact.sa_mask);
  407. assert (rs == 0);
  408. /* Call sa_sigaction, not sa_handler. */
  409. newact.sa_flags = SA_SIGINFO;
  410. /* In case we call user's handler on SIGSEGV (not bound
  411. violation exception) we want to allow bound checking
  412. inside the user handler -> nested exception. */
  413. newact.sa_flags |= SA_NODEFER;
  414. newact.sa_restorer = 0;
  415. r = sigaction (signum, &newact, 0);
  416. assert (r == 0);
  417. }
  418. /* Set constructor priority to two to make it run after the
  419. constructor in sigaction.c. */
  420. static void __attribute__ ((constructor (1005)))
  421. mpxrt_prepare (void)
  422. {
  423. __mpxrt_init_env_vars (&bndpreserve);
  424. setup_handler ();
  425. process_specific_init ();
  426. }
  427. static void __attribute__ ((destructor))
  428. mpxrt_cleanup (void)
  429. {
  430. __mpxrt_print_summary (num_bnd_chk, MPX_L1_SIZE);
  431. __mpxrt_utils_free ();
  432. process_specific_finish ();
  433. }