123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516 |
- /* mpxrt.c -*-C++-*-
- *
- *************************************************************************
- *
- * @copyright
- * Copyright (C) 2014, Intel Corporation
- * All rights reserved.
- *
- * @copyright
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Intel Corporation nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * @copyright
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
- * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- *
- **************************************************************************/
- #define __STDC_FORMAT_MACROS
- #include "config.h"
- #include <inttypes.h>
- #include <stdio.h>
- #include <string.h>
- #include <stdint.h>
- #include <stdbool.h>
- #include <signal.h>
- #include <assert.h>
- #include <stdlib.h>
- #include <sys/mman.h>
- #include <sys/prctl.h>
- #include <cpuid.h>
- #include "mpxrt-utils.h"
- #ifdef __i386__
- /* i386 directory size is 4MB */
- #define NUM_L1_BITS 20
- #define REG_IP_IDX REG_EIP
- #define REX_PREFIX
- #define XSAVE_OFFSET_IN_FPMEM sizeof (struct _libc_fpstate)
- #else /* __i386__ */
- /* x86_64 directory size is 2GB */
- #define NUM_L1_BITS 28
- #define REG_IP_IDX REG_RIP
- #define REX_PREFIX "0x48, "
- #define XSAVE_OFFSET_IN_FPMEM 0
- #endif /* !__i386__ */
- #define MPX_ENABLE_BIT_NO 0
- #define BNDPRESERVE_BIT_NO 1
- const size_t MPX_L1_SIZE = (1UL << NUM_L1_BITS) * sizeof (void *);
- struct xsave_hdr_struct
- {
- uint64_t xstate_bv;
- uint64_t reserved1[2];
- uint64_t reserved2[5];
- } __attribute__ ((packed));
- struct bndregs_struct
- {
- uint64_t bndregs[8];
- } __attribute__ ((packed));
- struct bndcsr_struct {
- uint64_t cfg_reg_u;
- uint64_t status_reg;
- } __attribute__((packed));
- struct xsave_struct
- {
- uint8_t fpu_sse[512];
- struct xsave_hdr_struct xsave_hdr;
- uint8_t ymm[256];
- uint8_t lwp[128];
- struct bndregs_struct bndregs;
- struct bndcsr_struct bndcsr;
- } __attribute__ ((packed));
- /* Following vars are initialized at process startup only
- and thus are considered to be thread safe. */
- static void *l1base = NULL;
- static int bndpreserve;
- static int enable = 1;
- /* Var holding number of occured BRs. It is modified from
- signal handler only and thus it should be thread safe. */
- static uint64_t num_bnd_chk = 0;
- static inline void
- xrstor_state (struct xsave_struct *fx, uint64_t mask)
- {
- uint32_t lmask = mask;
- uint32_t hmask = mask >> 32;
- asm volatile (".byte " REX_PREFIX "0x0f,0xae,0x2f\n\t"
- : : "D" (fx), "m" (*fx), "a" (lmask), "d" (hmask)
- : "memory");
- }
- static inline void
- xsave_state (struct xsave_struct *fx, uint64_t mask)
- {
- uint32_t lmask = mask;
- uint32_t hmask = mask >> 32;
- asm volatile (".byte " REX_PREFIX "0x0f,0xae,0x27\n\t"
- : : "D" (fx), "m" (*fx), "a" (lmask), "d" (hmask)
- : "memory");
- }
- static inline uint64_t
- xgetbv (uint32_t index)
- {
- uint32_t eax, edx;
- asm volatile (".byte 0x0f,0x01,0xd0" /* xgetbv */
- : "=a" (eax), "=d" (edx)
- : "c" (index));
- return eax + ((uint64_t)edx << 32);
- }
- static uint64_t
- read_mpx_status_sig (ucontext_t *uctxt)
- {
- uint8_t __attribute__ ((__aligned__ (64))) buffer[4096];
- struct xsave_struct *xsave_buf = (struct xsave_struct *)buffer;
- memset (buffer, 0, sizeof (buffer));
- memcpy (buffer,
- (uint8_t *)uctxt->uc_mcontext.fpregs + XSAVE_OFFSET_IN_FPMEM,
- sizeof (struct xsave_struct));
- return xsave_buf->bndcsr.status_reg;
- }
- static uint8_t *
- get_next_inst_ip (uint8_t *addr)
- {
- uint8_t *ip = addr;
- uint8_t sib;
- /* Determine the prefix. */
- switch (*ip)
- {
- case 0xf2:
- case 0xf3:
- case 0x66:
- ip++;
- break;
- }
- /* Look for rex prefix. */
- if ((*ip & 0x40) == 0x40)
- ip++;
- /* Make sure we have a MPX instruction. */
- if (*ip++ != 0x0f)
- return addr;
- /* Skip the op code byte. */
- ip++;
- /* Get the moderm byte. */
- uint8_t modrm = *ip++;
- /* Break it down into parts. */
- uint8_t rm = modrm & 7;
- uint8_t mod = (modrm >> 6);
- /* Init the parts of the address mode. */
- uint8_t base = 8;
- /* Is it a mem mode? */
- if (mod != 3)
- {
- /* Look for scaled indexed addressing. */
- if (rm == 4)
- {
- /* SIB addressing. */
- sib = *ip++;
- base = sib & 7;
- switch (mod)
- {
- case 0:
- if (base == 5)
- ip += 4;
- break;
- case 1:
- ip++;
- break;
- case 2:
- ip += 4;
- break;
- }
- }
- else
- {
- /* MODRM addressing. */
- switch (mod)
- {
- case 0:
- if (rm == 5)
- /* DISP32 addressing, no base. */
- ip += 4;
- break;
- case 1:
- ip++;
- break;
- case 2:
- ip += 4;
- break;
- }
- }
- }
- return ip;
- }
- static void
- handler (int sig __attribute__ ((unused)),
- siginfo_t *info __attribute__ ((unused)),
- void *vucontext,
- struct xsave_struct *buf __attribute__ ((unused)))
- {
- ucontext_t* uctxt;
- greg_t trapno;
- greg_t ip;
- uctxt = vucontext;
- trapno = uctxt->uc_mcontext.gregs[REG_TRAPNO];
- ip = uctxt->uc_mcontext.gregs[REG_IP_IDX];
- if (trapno == 5)
- {
- uint64_t status = read_mpx_status_sig (uctxt);
- uint64_t br_reason = status & 0x3;
- __mpxrt_write (VERB_BR, "Saw a #BR! status ");
- __mpxrt_write_uint (VERB_BR, status, 10);
- __mpxrt_write (VERB_BR, " at 0x");
- __mpxrt_write_uint (VERB_BR, ip, 16);
- __mpxrt_write (VERB_BR, "\n");
- switch (br_reason)
- {
- case 1: /* traditional BR */
- num_bnd_chk++;
- uctxt->uc_mcontext.gregs[REG_IP_IDX] =
- (greg_t)get_next_inst_ip ((uint8_t *)ip);
- if (__mpxrt_mode () == MPX_RT_STOP)
- exit (255);
- return;
- default:
- __mpxrt_write (VERB_BR, "Unexpected status with bound exception: ");
- __mpxrt_write_uint (VERB_BR, status, 10);
- __mpxrt_write (VERB_BR, "\n");
- break;
- }
- }
- else if (trapno == 14)
- {
- __mpxrt_write (VERB_ERROR, "In signal handler, trapno = ");
- __mpxrt_write_uint (VERB_ERROR, trapno, 10);
- __mpxrt_write (VERB_ERROR, ", ip = 0x");
- __mpxrt_write_uint (VERB_ERROR, ip, 16);
- __mpxrt_write (VERB_BR, "\n");
- exit (255);
- }
- else
- {
- __mpxrt_write (VERB_ERROR, "Unexpected trap ");
- __mpxrt_write_uint (VERB_ERROR, trapno, 10);
- __mpxrt_write (VERB_ERROR, "! at 0x");
- __mpxrt_write_uint (VERB_ERROR, ip, 16);
- __mpxrt_write (VERB_BR, "\n");
- exit (255);
- }
- }
- /* Using wrapper to the real handler in order to save the bnd regs
- using xsave before any unprefixed call. an unprefixed call to
- __i686.get_pc_thunk.bx is added by the linker in 32bit at the
- beginning of handler function since there are references to
- global variables. */
- static void
- handler_wrap (int signum, siginfo_t* si, void* vucontext)
- {
- /* Since the OS currently not handling chkptr regs.
- We need to store them for later use. They might be
- init due to unprefixed call,Jcc,ret. avoiding calling
- function since the function will be unprefixed as well. */
- uint8_t __attribute__ ((__aligned__ (64))) buffer[4096];
- struct xsave_struct *xsave_buf = (struct xsave_struct *)buffer;
- uint64_t mask = 0x18;
- uint32_t lmask = mask;
- uint32_t hmask = mask >> 32;
- asm volatile (".byte " REX_PREFIX "0x0f,0xae,0x27\n\t"
- : : "D" (xsave_buf), "m" (*xsave_buf),
- "a" (lmask), "d" (hmask)
- : "memory");
- handler (signum, si, vucontext, xsave_buf);
- }
- static bool
- check_mpx_support (void)
- {
- unsigned int eax, ebx, ecx, edx;
- unsigned int max_level = __get_cpuid_max (0, NULL);
- if (max_level < 13)
- {
- __mpxrt_print (VERB_DEBUG, "No required CPUID level support.\n");
- return false;
- }
- __cpuid_count (0, 0, eax, ebx, ecx, edx);
- if (!(ecx & bit_XSAVE))
- {
- __mpxrt_print (VERB_DEBUG, "No XSAVE support.\n");
- return false;
- }
- if (!(ecx & bit_OSXSAVE))
- {
- __mpxrt_print (VERB_DEBUG, "No OSXSAVE support.\n");
- return false;
- }
- __cpuid_count (7, 0, eax, ebx, ecx, edx);
- if (!(ebx & bit_MPX))
- {
- __mpxrt_print (VERB_DEBUG, "No MPX support.\n");
- return false;
- }
- __cpuid_count (13, 0, eax, ebx, ecx, edx);
- if (!(eax & bit_BNDREGS))
- {
- __mpxrt_print (VERB_DEBUG, "No BNDREGS support.\n");
- return false;
- }
- if (!(eax & bit_BNDCSR))
- {
- __mpxrt_print (VERB_DEBUG, "No BNDCSR support.\n");
- return false;
- }
- return true;
- }
- static void
- enable_mpx (void)
- {
- uint8_t __attribute__ ((__aligned__ (64))) buffer[4096];
- struct xsave_struct *xsave_buf = (struct xsave_struct *)buffer;
- memset (buffer, 0, sizeof (buffer));
- xrstor_state (xsave_buf, 0x18);
- __mpxrt_print (VERB_DEBUG, "Initalizing MPX...\n");
- __mpxrt_print (VERB_DEBUG, " Enable bit: %d\n", enable);
- __mpxrt_print (VERB_DEBUG, " BNDPRESERVE bit: %d\n", bndpreserve);
- /* Enable MPX. */
- xsave_buf->xsave_hdr.xstate_bv = 0x10;
- xsave_buf->bndcsr.cfg_reg_u = (unsigned long)l1base;
- xsave_buf->bndcsr.cfg_reg_u |= enable << MPX_ENABLE_BIT_NO;
- xsave_buf->bndcsr.cfg_reg_u |= bndpreserve << BNDPRESERVE_BIT_NO;
- xsave_buf->bndcsr.status_reg = 0;
- xrstor_state (xsave_buf, 0x10);
- }
- static void
- disable_mpx (void)
- {
- uint8_t __attribute__ ((__aligned__ (64))) buffer[4096];
- struct xsave_struct *xsave_buf = (struct xsave_struct *)buffer;
- memset(buffer, 0, sizeof(buffer));
- xrstor_state(xsave_buf, 0x18);
- /* Disable MPX. */
- xsave_buf->xsave_hdr.xstate_bv = 0x10;
- xsave_buf->bndcsr.cfg_reg_u = 0;
- xsave_buf->bndcsr.status_reg = 0;
- xrstor_state(xsave_buf, 0x10);
- }
- static bool
- process_specific_init (void)
- {
- if (!check_mpx_support ())
- return false;
- l1base = mmap (NULL, MPX_L1_SIZE, PROT_READ | PROT_WRITE,
- MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
- if (l1base == MAP_FAILED)
- {
- perror ("mmap");
- exit (EXIT_FAILURE);
- }
- enable_mpx ();
- if (prctl (43, 0, 0, 0, 0))
- {
- __mpxrt_print (VERB_ERROR, "No MPX support\n");
- disable_mpx ();
- return false;
- }
- return true;
- }
- static bool
- process_specific_finish (void)
- {
- if (!check_mpx_support ())
- return false;
- if (prctl (44, 0, 0, 0, 0))
- {
- __mpxrt_print (VERB_ERROR, "No MPX support\n");
- return false;
- }
- munmap (l1base, MPX_L1_SIZE);
- return true;
- }
- static void
- setup_handler (void)
- {
- int r,rs;
- struct sigaction newact;
- /* #BR is mapped to sigsegv */
- int signum = SIGSEGV;
- newact.sa_handler = 0;
- newact.sa_sigaction = handler_wrap;
- /* sigset_t - signals to block while in the handler
- get the old signal mask. */
- rs = sigprocmask (SIG_SETMASK, 0, &newact.sa_mask);
- assert (rs == 0);
- /* Call sa_sigaction, not sa_handler. */
- newact.sa_flags = SA_SIGINFO;
- /* In case we call user's handler on SIGSEGV (not bound
- violation exception) we want to allow bound checking
- inside the user handler -> nested exception. */
- newact.sa_flags |= SA_NODEFER;
- newact.sa_restorer = 0;
- r = sigaction (signum, &newact, 0);
- assert (r == 0);
- }
- /* Set constructor priority to two to make it run after the
- constructor in sigaction.c. */
- static void __attribute__ ((constructor (1005)))
- mpxrt_prepare (void)
- {
- __mpxrt_init_env_vars (&bndpreserve);
- setup_handler ();
- process_specific_init ();
- }
- static void __attribute__ ((destructor))
- mpxrt_cleanup (void)
- {
- __mpxrt_print_summary (num_bnd_chk, MPX_L1_SIZE);
- __mpxrt_utils_free ();
- process_specific_finish ();
- }
|