/GS in Action
The following C++ sample code has a buffer overflow—
bug—strcpy() copies more than 10
bytes into a 10-byte buffer:
#include "stdafx.h"
#include "stdio.h"
#include "string.h"
void main() {
char szTemp[10];
strcpy(szTemp,"Hello, Big ol' World!");
puts(szTemp);
}
When this code is compiled and executed with debug data and the
/GS option, you'll see the
dialog box shown in
Figure 3.

Figure 3. Buffer Overflow Error Message from Visual Studio Debugger. |
|

Figure 4. Buffer Overflow Error Message from Visual C++ Runtime Library. |
It's actually quite a useful error because it informs you of the variable that clobbered the stack. Clicking the Break
button will load the application into the debugger. At this point, you should look at the
szTemp variable and find the code and data that led up to the buffer being overflowed.
If the same code is compiled with the /GS switch but without debug data and then executed,
you'll see the dialog box shown in Figure 4.
Once you hit OK, the application will halt. You can write your own version of the security error handler function and override the default security handler by calling _set_security_error_handler() early in your application. It may be useful during development to simply call DebugBreak() (or call the x86 assembly language instruction int 3) within the handler to get a clean stack-trace, especially if the application has no user interface like a Windows service.
The following code shows how to set a new handler:
#include "stdafx.h"
#include "stdio.h"
#include "string.h"
#include "stdlib.h"
__cdecl _myhandler(int iErr, void *pErr) {
if (iErr == _SECERR_BUFFER_OVERRUN)
__asm int 3;
}
void main() {
_set_security_error_handler(_myhandler);
char szTemp[10];
strcpy(szTemp,"Hello, Big ol' World!");
puts(szTemp);
}
|
Author's Note: In beta 1, iErr is always _SECERR_BUFFER_OVERRUN and *pErr is always NULL. |
For performance reasons, not all functions have the cookie and function epilog code. During compilation, the compiler determines which functions should be protected using two rules:
- The function must be called by another function that passes pointer data.
- The function must have more than eight bytes of stack-allocated buffers.
If you're wondering how performance will be effected, don't worry. Microsoft's internal lab tests on both client and server applications have shown that the overall performance impact is very small, in the order of 1 percent CPU time. Not bad for the extra protection.
The Bottom Line
There is no substitute for good programming skills and peer code review for discovering and fixing vulnerable code.
That said, the new /GS option in the new Microsoft Visual C++.NET compiler will help reduce the instances of
exploitable buffer overruns in your Windows application code. However, if your application does halt because someone
finds a buffer overrun, fix it quickly—and learn from the mistake.