Partager via


Hardening Stack-based Buffer Overrun Detection in VC++ 2005 SP1

As y’all know, the Visual C++ /GS compiler flag adds prolog and epilog code to certain functions to help detect some classes of stack based buffer overruns at runtime. In VC++ 2005, the code looks like this:

Function prolog

sub esp, 8

mov eax, DWORD PTR ___security_cookie

xor eax, esp

mov DWORD PTR __$ArrayPad$[esp+8], eax

mov eax, DWORD PTR _input$[esp+4]

Function epilog

mov ecx, DWORD PTR __$ArrayPad$[esp+12]

add esp, 4

xor ecx, esp

call @__security_check_cookie@4

add esp, 8

__security_cookie is a pseudo-random number created when the image loads.

In the overall scheme of things, we see little if any performance degradation because of the /GS. But there are a set of heuristics you should be aware when compiling with /GS. In short, the compiler does not apply the stack cookie code to all functions; it applies a set of heuristics to determine which functions should get the stack cookie treatment. Read the /GS documentation <https://msdn2.microsoft.com/en-US/library/8dbf701c.aspx> for an explanation of the compiler heuristics.

In Visual C++ 2005 SP1, we added a new pragma that makes the -GS flag much more aggressive. The syntax is:

#pragma strict_gs_check([push,] on )
#pragma strict_gs_check([push,] off )
#pragma strict_gs_check(pop)

Personally, I enable this at the top of any source code file that includes functions highly susceptible to attack or code that handles untrusted data.

Here’s a quick code sample. The code has a buffer overrun copying an array to a local array, but when it is compiled with /GS, no cookie is inserted in the stack because the array data type is an unsigned integer. Adding the strict_gs_check pragma forces the stack cookie into the function stack.

#pragma strict_gs_check(on)

unsigned int * ReverseArray(__in_ecount(cData) unsigned int *pdwData, size_t cData) {
unsigned int dwReversed[20]; // *** This buffer is subject to being overrun!! ***
// Reverse the array into a temporary buffer

for (size_t j=0, i = cData; i ; --i, ++j)
dwReversed[j] = pdwData[i]; // *** Possible buffer overrun!! ***

// Copy temporary buffer back into input/output buffer
for (size_t i = 0; i < cData ; ++i)
pdwData[i] = dwReversed[i];

return pdwData;
}

Also, functions with stack-based buffers that are less than 4-bytes long will also get a cookie.

As a result of applying this pragma to some sample code, there was an increase from 39 to 56 functions protected by the GS cookie out of a total of 761 functions. For high-attack surface components, which often listen on the network, the extra performance overhead due to such a small number of extra GS checks is negligible, but the extra defensive layer is valuable.

Comments

  • Anonymous
    April 04, 2007
    PingBack from http://chrisweber.wordpress.com/2007/04/04/hardening-stack-based-buffer-overrun-detection-in-vc-2005-sp1/

  • Anonymous
    April 04, 2007
    Do Microsoft care to explain what 'If a parameter is used only in ways that are less likely to be exploitable in the event of a buffer overrun.' means?

  • Anonymous
    April 05, 2007
    The sample code above shows the main one - using non-chars as the buffer element type

  • Anonymous
    April 10, 2007
    Is this correct that /GS can make copies of vulnerable parameters on stack, and thus increase stack usage much more and less predictably than we could guess? (8 bytes per call frame) Is there any easy way to know when the compiler makes big allocations on stack? This may be important for kernel mode, where stack is limited.

  • Anonymous
    April 10, 2007
    ddebug, yes it's true, but in our experience, it's really not a big issue. We saw now perf problems or stack exhaustion.

  • Anonymous
    April 18, 2007
    Does using this flag enable /GS cookies for the LoadAniIcon function which was responsible for the recent ANI vulnerability? It was a perfect example of a function which should have been protected by /GS, but the compiler failed to insert the cookie because the function was overwriting a structure on the stack, instead of an array. By the way, what exact version of VC2005 was used to compile Vista? Is it the same one that's included in the Vista release of the Windows SDK, or a private build of the compiler?

  • Anonymous
    April 18, 2007
    Hello Alexander re: /GS - yes, the #pragma would add the cookie to this func.

  • Anonymous
    April 26, 2007
    Michael Howard here. A core tenet of the SDL is to take and incorporate lessons learned when we issue

  • Anonymous
    April 28, 2007
    I have VS2005 SP1 running, but the compiler complains that this pragma simply doesn't exist. What now?