How to Protect Apps from Buffer Overflow Attacks

Introduction

Beginning with the Intel® 6th generation Core™ processor, Intel has introduced Intel® Memory Protection Extensions (Intel® MPX), a new extension to the instruction set architecture that aims to enhance software security by helping to protect against buffer overflow attacks. In this article, we discuss buffer overflow, and then give step-by step details on how application developers can prevent their apps from suffering from buffer overflow attacks on Windows® 10. Intel MPX works for both traditional desktop apps and Universal Windows Platform* apps.

Prerequisites

To run the samples discussed in this article, you’ll need the following hardware and software:

  • A computer (desktop, laptop, or any other form factor) with Intel® 6th generation Core™ processor and Microsoft Windows 10 OS (November 2015 update or greater; Windows 10 version 1607 is preferred)
  • Intel MPX enabled in UEFI (if the option is available)
  • Intel MPX driver properly installed
  • Microsoft Visual Studio* 2015 (update 1 or later IDE; Visual Studio 2015 update 3 is preferred)

Buffer Overflow

C/C++ code is by nature more susceptible to buffer overflows. For example, in the following code the string operation function “strcpy” in main() will put the program at risk for a buffer overflow attack.

#include "stdafx.h"
#include <iostream>
#include <time.h>
#include <stdlib.h> 

using namespace std;

void GenRandomUname(char* uname_string, const int uname_len)
{
	srand(time(NULL));
	for (int i = 0; i < uname_len; i++)
	{
		uname_string[i] = (rand() % ('9' - '0' + 1)) + '0';
	}
	uname_string[uname_len] = '\0';
}

int main(int argnum, char** args)
{
	char user_name[16];
	GenRandomUname(user_name, 15);
	cout << "random gentd user name: " << user_name << endl;

	char config[10] = { '\0' };
	strcpy(config, args[1]);

	cout << "config mem addr: " << &config << endl;
	cout << "user_name mem addr: " << &user_name << endl;

	if (0 == strcmp("ROOT", user_name))
	{
		cout << "Buffer Overflow Attacked!" << endl;
		cout << "Uname changed to: " << user_name << endl;
	}
	else 
	{
		cout << "Uname OK: " << user_name << endl;
	}
	return 0;
}

To be more accurate, if we compile and run the above sample as a C++ console application, passing CUSM_CFG as an argument, the program will run normally and the console will show the following output:

Figure 1 Buffer Overflow

But if we rerun the program passing CUSTOM_CONFIGUREROOT as an argument, the output will be “unexpected” and the console will show a message like this:

Figure 2 Buffer Overflow

This simple example shows how a buffer overflow attack works. The reason why there can be unexpected output is that the function call of strcpy does not check the bonds of the destination array. Although compilers usually give several extra bytes to arrays for memory alignment purpose, buffer overflow may still happen if the source array is long enough. In this case, a piece of the runtime memory layout of the program looks like this (the result of different compilers or compile options may vary):

Figure 3

Intel Memory Protection Extensions

With the help of Intel MPX, we can avoid the buffer overflow security issue simply by adding the compile option /d2MPX to the Visual Studio C++ compiler.

Figure 4

After recompiling with the Intel MPX option, the program is able to defend against buffer overflow attacks. If we try running the recompiled program with CUSTOM_CONFIGUREROOT argument, a runtime exception will arise and cause the program to exit.

Figure 5

Let’s dig into the generated assembly code to see what Intel MPX has done with the program. From the results, we can see that many of the instructions related to Intel MPX have been inserted into the original instructions to detect buffer overflows at runtime.

Figure 6

Now let’s look in more detail at the instructions related to Intel MXP:

bndmk: Creates LowerBound (LB) and UpperBound (UB) in the bounds register (%bnd0) in the code snapshot above.
bndmov: Fetches the bounds information (upper and lower) out of memory and puts it in a bounds register.
bndcl: Checks the lower bounds against an argument (%rax) in the code snapshot above.
bndcu: Checks the upper bounds against an argument (%rax) in the code snapshot above.

Troubleshooting

If MPX is not working properly,

  1. Double-check the versions of your CPU, OS, and Visual Studio 2015. Boot the PC into the UEFI settings to check if there is any Intel MPX switch; turn on the switch if needed.
  2. Confirm that the Intel MPX driver is properly installed and functioning properly in the Windows* Device Manager. Figure 7
  3. Check that the compiled executable contains instructions related to Intel MPX. Insert a break point, and then run the program. When the break point is hit, right-click with the mouse, and then click Go To Disassembly. A new window will display for viewing the assembly code.

Figure 8

Conclusion

Intel MPX is a new hardware solution that helps defend against buffer overflow attacks. Compared with software solutions such as AddressSanitizer (https://code.google.com/p/address-sanitizer/), from an application developer’s point of view, Intel MPX has many advantages, including the following:

  • Detects when a pointer points out of the object but still points to valid memory.
  • Intel MPX is more flexible, it can be used in some certain modules without affecting any other modules.
  • Compatibility with legacy code is much higher for code instrumented with Intel MPX.
  • One single version binary can still be released, because of the particular instruction encoding. The instructions related to Intel MPX will be executed as NOPs (No Operations) on unsupported hardware or operations systems.

On Intel® 6th generation Core™ Processor and Windows 10, benefiting from Intel MPX for applications is as simple as adding a compiler option, which can help enhance application security without hurting the application’s backward compatibility.

Related Articles

Intel® Memory Protection Extensions Enabling Guide:

https://software.intel.com/en-us/articles/intel-memory-protection-extensions-enabling-guide

References

[1] AddressSanitizer: https://code.google.com/p/address-sanitizer/

[2] VC++ blog on MPX from MSDN: https://blogs.msdn.microsoft.com/vcblog/2016/01/20/visual-studio-2015-update-1-new-experimental-feature-mpx/

About the Author

Fanjiang Pei is an application engineer in the Client Computing Enabling Team, Developer Relations Division, Software and Solutions Group (SSG). He is responsible for enabling security technologies of Intel such as Intel MPX, Intel® Software Guard Extensions, and more.

For more complete information about compiler optimizations, see our Optimization Notice.