Intel® Memory Protection Extensions (Intel® MPX) support in the GNU toolchain

Published:07/22/2013   Last Updated:07/22/2013

NOTE: Intel® Memory Protection Extensions (Intel® MPX) have been deprecated and are not available on all future processors.

Invalid memory access problem is commonly found in many C/C++ programs and leads to time consuming debugging, program instability and vulnerability. Many attacks exploit software bugs related to inappropriate memory accesses caused by buffer overflow (or buffer overruns). Existing set of techniques/tools to find such memory bugs in the programs and defend them from the attacks are software only solutions which result in poor performance of the protected code.

 

Intel® is introducing a new ISA extension called Intel® Memory Protection Extensions (Intel® MPX) (see latest Programming Reference manual posted here under Related Specifications) to be used for memory protection in applications with low performance overhead. To get the advantage of new extension, changes are required in the OS kernel, binutils, compiler, system libraries support.

 

This paper describes changes in GNU Binutils, GCC and Glibc to support Intel® MPX.

 

Intel® MPX introduces new registers called bound registers to hold bounds for a pointer and instructions to manipulate those registers (for details see the Programming Reference). Therefore the first step is to implement support for new hardware features in binutils and the GCC.

 

The second step in Intel® MPX support is implementation of Intel® MPX instrumentation pass in the GCC compiler which is responsible for instrumenting all memory accesses with pointer checks. Compiler changes for runtime bound checks include:

 

  • Bounds creation for statically allocated objects, objects allocated on the stack and statically initialized pointers

 

  • Intel® MPX support in ABI: ABI extension allows passing bounds for the pointers passed as function arguments and provide returned bounds with the pointers (see the posted Linux ABI document under Intel® MPX Technical Content at http://software.intel.com/en-us/intel-isa-extensions)

 

  • Bounds table content management: each pointer is stored into the memory should have its bounds stored in the corresponding row of the bounds table; compiler generates appropriate code to have the bounds table in the consistent state

 

  •  Memory accesses instrumentation: compiler analyzes data flow to compute bounds corresponding to each memory access and inserts code to check used address against computed bounds

 

Dynamically created objects in heap using memory allocators need to set bounds  for objects (buffers) at allocation time. So the next step is to add Intel® MPX support into standard memory allocators in Glibc.

 

To have the full protection, an application has to use libraries compiled with Intel® MPX instrumentation. It means we had to compile Glibc with the Intel® MPX enabled GCC compiler because it is used in most applications. Also we had to add Intel® MPX instrumentation to all the necessary Glibc routines (e.g. memcpy) written on assembler.

 

We introduce new option –fmpx in the GCC to utilize Intel® MPX instructions. Also binutils with Intel® MPX enabled should be used to get binaries with memory protection.

 

Consider following simple test for MPX compiled program:

       int main(int argc, char* argv)

       {

           int buf[100];

           return buf[argc];

       }

Snippet of the original assembler output (compiled with -O2):

       movslq  %edi, %rdi

       movl    -120(%rsp,%rdi,4), %eax    // memory access buf[argc]

 

Compile test as follows: mpx-gcc/gcc  test.c   -fmpx –O2.

Resulted assembler snippet:

        movl    $399, %edx                           // load array length to edx

 

        movslq  %edi, %rdi                           // rdi contains value of argc

 

        leaq    -104(%rsp), %rax                   // load start address of buf to rax

 

        bndmk   (%rax,%rdx), %bnd0           //  create bounds for buf

 

        bndcl   (%rax,%rdi,4), %bnd0     // check that memory access doesn’t violate buf’s low bound

 

        bndcu   3(%rax,%rdi,4), %bnd0  // check that memory access doesn’t violate buf’s upper bound

 

        movl    -104(%rsp,%rdi,4), %eax  // original memory access

 

Code looks pretty clear. Note only that we added displacement 3 for upper bound checking since we have 4 byte (integer) access here.

 

Another simple example demonstrates using of bndldx and bndstx instructions.

      extern int * p;

      extern int * q;

      int foo( int c)

      {

           q = p;

           return p[c];

      }

 

After compilation with –O2 –fmpx we have such piece of assembler code:

        movq    p(%rip), %rax

 

        movslq  %edi, %rdi

 

        bndldx  p(,%rax), %bnd0             // load bounds for pointer p into bnd0

 

        movq    %rax, q(%rip)                  // q=p

 

        bndstx  %bnd0, q(,%rax)             // we need now to update bound information for q

 

        leaq    (%rax,%rdi,4), %rax

 

        bndcl   (%rax), %bnd0

 

        bndcu   3(%rax), %bnd0

 

        movl    (%rax), %eax

 

 

 

Several Intel® MPX specific compiler options besides –fmpx were introduced in the compiler. Most of them, like -fmpx-check-read and -fmpx-check-write, control number of inserted runtime bound checks. Also developers always can use intrinsics to insert Intel® MPX instructions manually. To see full set of Intel® MPX specific options and intrinsics added to the compiler check GCC Wiki page

Currently GCC compiler sources with Intel® MPX support is available in a separate branch in common GCC SVN repository. See GCC SVN page for details.

Currently no hardware with Intel® MPX ISA is available but it is always possible to use Intel® SDE instead, which can be downloaded from http://software.intel.com/en-us/articles/intel-software-development-emulator

Product and Performance Information

1

Intel's compilers may or may not optimize to the same degree for non-Intel microprocessors for optimizations that are not unique to Intel microprocessors. These optimizations include SSE2, SSE3, and SSSE3 instruction sets and other optimizations. Intel does not guarantee the availability, functionality, or effectiveness of any optimization on microprocessors not manufactured by Intel. Microprocessor-dependent optimizations in this product are intended for use with Intel microprocessors. Certain optimizations not specific to Intel microarchitecture are reserved for Intel microprocessors. Please refer to the applicable product User and Reference Guides for more information regarding the specific instruction sets covered by this notice.

Notice revision #20110804