Security Stuff in Whidbey - More Secure Buffer Function Calls: AUTOMATICALLY!

In my previous blog I very briefly touched on the new C runtime library added to Whidbey.

 

Take a look at the following simple code:

 

int main(int argc, char* argv[]) {

    char t[10];

       ...

    if (2==argc)

strcpy(t,argv[1]);

 

       ...

    return 0;

}

 

As you can see there is a bug on the third line, the code is copying untrusted input to a stack-based buffer. A classic “Stack Smash.” On Windows, this would generally not be a security bug as the code can only run as you. But if this were in an elevated process, such as a setuid root application on Linux, Mac OS X or Unix, then this would be a bad security bug requiring a fix. Here are a couple of examples:

 

https://secunia.com/advisories/13965/

https://secunia.com/advisories/12481/

 

And just to show you the compiler is doing the ‘right’ thing by generated code ‘as implemented’ here’s a snippet of the ASM file generated by the compiler:

 

; 9 : char t[10];

; 10 : strcpy(t,argv[1]);

      mov eax, DWORD PTR _argv$[esp+12]

      mov eax, DWORD PTR [eax+4]

      lea edx, DWORD PTR _t$[esp+16]

      sub edx, eax

      npad 6

$LL3@main:

      mov cl, BYTE PTR [eax]

      mov BYTE PTR [edx+eax], cl

      add eax, 1

      test cl, cl

      jne SHORT $LL3@main

 

The loop from $LL3@main is an inline strcpy. Trust me!

 

A more secure version would look a little like this:

 

int main(int argc, char* argv[]) {

    char t[10];

      ...

    if (2==argc)

strncpy(t,argv[1],10);

 

      ...

    return 0;

}

 

Of better yet, you could use the Safer CRT:

 

int main(int argc, char* argv[]) {

    char t[10];

       ...

    if (2==argc)

strcpy_s(t,_countof(t)argv[1]);

 

       ...

    return 0;

}

 

Now let’s say for a moment that you don’t change the function call from strcpy to strcpy_s, because you either missed it, or simply don’t want to tinker with the source too much. There’s a cool new feature for C++ code in Whidbey. If you add the following to your stdafx.h header:

 

#define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES 1

 

Recompile the code, and then look at the ASM file again:

 

; 9 : char t[10];

; 10 : strcpy(t,argv[1]);

      mov eax, DWORD PTR [eax+4]

      push eax

      lea ecx, DWORD PTR _t$[esp+20]

      push 10 ; 0000000aH

      push ecx

      call DWORD PTR __imp__strcpy_s

 

Well lookie here – the compiler knows the size of the destination buffer, so it automatically replaces the strcpy with a strcpy_s.

 

Very cool stuff... :)