Buffer Overruns and the Common Language Runtime

Buffer Overruns and the Common Language Runtime

When investigating buffer overruns as I often do, much to my chagrin you realize they are primarily a C and C++ problem, because these languages are one notch above the metal and were designed for speed and flexibility, including direct access to system memory. Buffer overruns exist in other languages, but they tend to be bugs in the run-time engine or libraries, rather than in user code.

The good news is that the managed code environment dramatically reduces the chance of buffer overruns in your code. But, C and C++ won t disappear overnight, and managed code can call unmanaged code. Unmanaged code is the same as any C or C++ code you write today and, as such, could be susceptible to many of the classic security vulnerabilities we know and loathe.

The really good news is that Microsoft Visual C++ .NET includes a new feature that helps mitigate some kinds of exploitable buffer overruns. That said, there is simply no substitute for good, secure programming practices, but sometimes this isn t enough. We are human, we make mistakes, and we leave vulnerable code in our applications!

Enter the new /GS option in Visual C++ .NET. This new option, called the buffer security check, inserts special code into the application or DLL startup code, as well as special code into certain functions prolog and epilog code.

What Is Function Prolog and Epilog Code?

As the name implies, prolog and epilog code is code located at the start and end of a function call. If you look at the assembly language output from a C or C++ source code file compiled with the /GS option, you ll notice that code that has the new buffer overrun code enabled has some extra instructions to set the random cookie data in the stack at the start of the function. This is the function prolog code. The code also includes a call to __security_check_cookie at the end of the function. This is the function epilog code.

This new compile-time option adds special data, called a cookie or a canary, into the stack between the local data and the return address for the function. The value of the cookie is random and is determined in the startup code for a process or dynamic-link library. When the function returns, the cookie is checked. If it has changed, a special error handler function is called that, by default, halts the process. It s better to stop the application rather than run the risk of an attacker injecting and executing code in your process. Figure 13-1 shows a simplified stack layout with a canary inserted.

Figure 13-1

A simplified stack layout and inserting a canary into a stack.

More good news: the /GS option is enabled by default for new C++ projects. However, if you need to set this option, just follow these steps from within your Visual C++ .NET project:

  1. Click View, and select Solution Explorer.

  2. Right-click the project name in the Solution Explorer.

  3. Select Properties to open the Property Pages dialog box.

  4. Expand the Configuration Properties node, if it is not already expanded, and then expand the C/C++ node.

  5. Click Code Generation.

  6. Make sure Release is selected in the Configuration drop-down list box at the top left of the Property Pages dialog box.

  7. Select Yes (/GS) in the Buffer Security Check option.

Figure 13-2 shows the project s Property Pages dialog box with the Buffer Security Check option enabled.

Figure 13-2

The Buffer Security Check option enabled.

Note that for a debug build you don t need to select this option, because the /RTC1 option, a superset of /GS, is enabled by default. This option also detects uninitialized variables at run time and stack pointer corruption.

note

The /GS option is for unmanaged C and C++ code only. The option has no effect on managed code.

You re probably wondering what the performance impact is with the /GS option enabled. The impact is minimal because not all functions are impacted, only functions with stack-based buffers. From speaking with various groups that have used this option, the worst performance impact I found was slightly over 1.3 percent for a highly stressed server-based application and well below the statistical noise for client applications.

Adding Your Own Security Error Handler

As a developer, you might not want the process to stop executing when a stack-based buffer overrun is encountered. You can write your own version of the security error handler function and override the default security handler by calling _set_security_error_handler, with a pointer to your handler function. Look up _set_security_error_handler in the Microsoft Visual Studio .NET online documentation for more information.

A Dose of Reality

The /GS option is a significant advancement for security in Windows-based C and C++ applications, but simply setting this option does not fix buffer overruns. First, doing so catches only stack-based buffer overruns that overwrite the function return address. It does not detect heap-based buffer overruns, nor does it detect buffer overruns that do not overwrite the return address. For example, a function has a buffer and a function pointer on the stack, and the buffer overwrites the buffer and the function pointer. Take a look at the following contrived code. (I say contrived because most good C++ compilers, including Microsoft s offerings, will optimize the bug away.)

void foo() { // Do something. } void CopyData(char *bBuff, int cbBuff) { char bName[128]; void (*func)() = foo; memcpy(bName, bBuff, cbBuff); (func)(); }

If bBuff is larger than bName and big enough to overwrite the pointer to foo held in the variable func but not big enough that the canary is overwritten, the address held in func can be changed to point to the start of the buffer, bName, which could contain the attacker s malicious code.

That said, this new compile-time option is a wonderful defensive mechanism to add to your unmanaged C and C++ projects. At the very least you should enable this option and carry out a performance analysis on the results to see whether it s efficient enough for you. I think you ll be delighted by the feature and use it!



Writing Secure Code
Writing Secure Code, Second Edition
ISBN: 0735617228
EAN: 2147483647
Year: 2005
Pages: 153

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net