本文将会介绍MPX(Memory Protection Extensions) 的基本概念。

motivation

The C and C++ languages provide for memory access via pointers, however, these languages do not ensure the safe use of pointers. Left undetected, the unsafe use of pointers puts an application at risk of data corruption or malicious attack via buffer overruns and overflows.

Unfortunately, all the existing software-based solutions to this problem exhibit high performance overheads preventing them from wide adoption in production runs. To address this issue, Intel released a new ISA extension—Memory Protection Extensions (Intel MPX), a hardware-assisted full-stack solution to protect against memory safety violations.

overview

Intel MPX is a set of processor features which, with compiler, runtime library and OS support, brings increased robustness to software by checking pointer references whose compile time normal intentions are usurped at runtime due to buffer overflow.

Intel MPX requires modifications at each level of the hardware-software stack:

  • At the hardware level new instructions as well as a set of 128-bit registers are added. Also, a bounds violation exception (#BR) thrown by these new instructions is introduced.
  • At the OS level, a new #BR exception handler is added that has two main functions: (1) allocating storage for bounds on-demand and (2) sending a signal to the program whenever a bounds violation is detected.
  • At the compiler level, new Intel MPX transformation passes are added to insert MPX instructions to create, propagate, store, and check bounds. Additional runtime libraries provide initialization/finalization routines, statistics and debug info, and wrappers for functions from C standard library.
  • At the application level, the MPX-protected program may require manual changes due to unconventional C coding patterns, multithreading issues, or potential problems with other ISA extensions.(In some cases, it is inadvisable to use Intel MPX at all.)

example


The sole purpose of Intel MPX is to transparently add bounds checking to legacy C/C++ programs. Consider a code snippet in Figure 2a. The original program allocates an array a[10] with 10 pointers to some buffer objects of type obj (Line 1). Next, it iterates through the first M items of the array to calculate the sum of objects’ length values (Lines 3–8). In C, this loop would look like this:

for (i=0; i<M; i++) total += a[i]−>len;

Since M is a variable, a bug or a malicious activity may set M to a value that is larger than obj size and an overflow will happen. Also, note how the array item access a[i] decays into a pointer ai on Line 4, and how the subfield access decays to lenptr on Line 6.

Figure 2b shows the resulting code with Intel MPX protection applied. First, the bounds for the array a[10] are created on Line 3 (the array contains 10 pointers each 8 bytes wide, hence the upper-bound offset of 79). Then in the loop, before the array item access on Line 8, two MPX bounds checks are inserted to detect if a[i] overflows (Lines 6–7). Note that since the protected load reads an 8-byte pointer from memory, it is important to check ai+7 against the upper bound (Line 7).

Now that the pointer to the object is loaded in objptr, the program wants to load the obj.len subfield. By design, Intel MPX must protect this second load by checking the bounds of the objptr pointer. Where does it get these bounds from? In Intel MPX, every pointer stored in memory has its associated bounds also stored in a special memory region accessed via bndstx and bndldx MPX instructions . Thus, when the objptr pointer is retrieved from memory address ai, its corresponding bounds are retrieved using bndldx from the same address (Line 9). Finally, the two bounds checks are inserted before the load of the length value on Lines 11–12.


参考资料:

  1. Introduction to Intel® Memory Protection Extensions
  2. Intel MPX Explained