This post is about Intel® Memory Protection Extensions (Intel® MPX) support in Microsoft Visual Studio* 2015; content provided by Gautham Beeraka, George Kuan, and Juan Rodriguez from Intel Corporation.
Update 1 for Visual Studio 2015 was announced on November 30, 2015. This update includes experimental compiler and debugger support for Intel MPX. Intel MPX can check all pointer reads and writes to ensure they remain within their declared memory bounds. This technology can detect buffer overflows and stop program execution at runtime, averting possible system compromises. It enables C/C++ code to make use of the new MPX instruction set and registers introduced in the 6th Generation Intel® Core™ Processors (“MPX-enabled platform”).
The Microsoft Visual C++ Compiler* and linker can now generate checks automatically, a capability enabled by specifying a command line option.
This blog explains how you can use automatic MPX code generation and debug MPX-enabled binaries. For more details on Intel MPX, please see the Intel MPX Technology web page.
How to enable automatic MPX code generation
Visual Studio 2015 Update 1 introduces a new compiler option: /d2MPX.
/d2MPX currently supports:
- Checking memory writes for potential buffer overflows. This provides protection for local and global pointers and arrays.
- Extensions to the calling conventions to automatically propagate bounds associated with pointer arguments.
To enable automatic MPX code generation for your project:
In Visual Studio, add the /d2MPX option in the Additional Options box (Project|Properties|Configuration Properties|C/C++|Command Line|Additional Options), Figure 1.
The following example is a program that contains an illustrative buffer overflow
In Figure 2, the statement inside of the for loop would have overflowed the out array when it attempts to write past the end of the array since out is smaller than string str. Just before the program would have performed the out-of-bounds store, the MPX hardware will generate a #BR (bound range exceeded) exception, which is manifested as a structured exception handling (SEH) exception “Array bounds exceeded”. The default behavior in absence of an exception handler for the array bounds exceeded exception is immediate termination of the program. Alternatively, one can add an exception handler as shown in the example code to log the exception or to perform some context dependent recovery such as tearing down the process all the while having avoided the out-of-bounds store.
Steps to build and run the example:
Check that the Intel® MPX Runtime Driver is installed on your Microsoft® Windows® 10 November 2015 Update or greater system by verifying its presence in Device Manager under System devices (Figure 3). If it is absent, please download and install the driver from the Intel® Memory Protection Extensions Enabling Guide.
Install Visual Studio 2015 Update 1. Note, if Visual Studio is installed with the phone emulators, Hyper-V will have to be disabled (bcdedit /set hypervisorlaunchtype off and reboot) because this version of Windows does not expose MPX instructions to the guest.
Create a Win32 Console Application named “MPXExample” and use the code in Figure 2 for the driver code.
As noted above, please, double check that the /d2MPX option is enabled for the current Configuration.
Build the project for the X64 platform from within Visual Studio. This should produce an MPXExample.exe binary.
Execute the binary MPXExample.exe on an MPX-enabled platform with Windows 10 – which has the OS support for MPX.
- To have the Visual Studio Debugger break on the array bounds exceeded exception, please enable the option for “Array bounds exceeded” in Exception Settings (Debug|Windows|ExceptionSettings) as shown in Figure 4. Executing MPXExample.exe in the debugger should now break on the exception (Figure 5). In this example, the #BR exception is thrown when MPX detects that we are about to write beyond the upper bound of the out array (Figure 6).
Figure 3. Verify that the Intel MPX Runtime Driver is installed via Device Manager.
Figure 4. Enable break on the array bounds exceeded exception in the Exception Settings window to have the Visual Studio Debugger break on the exception.
Figure 5. The Visual Studio Debugger breaks on the array bounds exceeded exception.
Figure 6. The exception is thrown when checking the upper bound as shown in this snapshot of the Disassembly window.
Visual Studio 2015 Update 1 supports the display and manipulation of the MPX registers via both the Register (Figure 7) and Watch windows (Figure 8) when running on an MPX-enabled platform.
Figure 7. To observe the contexts of the MPX bounds registers, enable MPX in the Debugger Register window.
Figure 8. Adding a bounds register to the Debugger Watch window is also simple. BND0.UB and BND0.LB in the Watch window refer to the upper and lower bounds in the BND0
register respectively. Note that the upper bound of a bounds register is displayed in 2’s complement form.
How to tell if a binary is MPX-enabled
Run dumpbin /headers MPXExample.exe. The MPX debug directory entry should be similar to what is shown in Figure 9.
Figure 9. To tell if a binary is MPX-enabled, check whether a binary includes the mpx debug directory using dumpbin. The mpx debug directory should be listed in the Debug Directories section in the dumpbin output.
Must I compile everything with MPX?
You don’t have to compile all of your code with MPX enabled. A mixture of MPX and non-MPX enabled code will execute correctly. However, code compiled without MPX support will not have any MPX checks.
What hardware and version of Windows do I need?
To gain the benefits of MPX, MPX-enabled code should be executed on an MPX-enabled platform running a version of the Windows Operating System that is MPX aware. As of today, MPX is supported on the following:
What if I execute MPX-enabled code on a platform or on a version of Windows
that does not support MPX?
The MPX-enabled code will execute correctly, but it will not benefit from MPX. You need to execute the code on an MPX-enabled platform with an MPX-aware operating system. The MPX instructions will be treated as NOPs, so you might experience a performance decrease in these scenarios.
MPX technology provides a powerful safeguard against buffer overflow. Inserting checks for every write to memory may incur some execution time and memory footprint overhead. The amount of overhead is tolerable during testing. However, when enabled for production code, the developer must balance whether the improved memory safety outweighs their customers’ performance needs. We plan to improve performance based on feedback.
There is a known issue with x86 debug build where debug instrumentation interferes MPX operation.
More Information and Feedback
For more information on how Intel MPX works, details on MPX intrinsic functions, calling convention extensions, and runtime behavior of MPX, please refer to the Intel® Memory Protection Extensions Enabling Guide.
Please try out automatic MPX code generation in Visual Studio 2015 Update 1. We are eager to hear about your experiences, especially in terms of usability, code size and runtime performance impact, and your suggestions for how to improve this feature. Please leave feedback in the comment box below or at the Intel ISA Extensions Forum on Intel® Developer Zone.
Intel technologies’ features and benefits depend on system configuration and may require enabled hardware, software or service activation. Performance varies depending on system configuration. Check with your system manufacturer or retailer or learn more at Intel MPX Technology web page. Intel, the Intel logo, 6th Generation Intel® Core are trademarks of Intel Corporation in the U.S. and/or other countries. *Other names and brands may be claimed as the property of others. © 2016 Intel Corporation