Security Enhancements in Visual C++
by Priyali Vibhute, BS 7799 LA | Discuss this article »» (1)
Microsoft added several security enhancements in Visual C++ recently: secure versions of vulnerable functions, new functions optimized for security and security switches for the compiler. This article introduces these features and helps developers use them immediately.
Secure versions of vulnerable functions
Visual C++ 2005 introduces newer, secure versions for vulnerable functions like strcpy(), sprintf() and others. Let’s take a quick look at the vulnerabilities associated with these functions and how the secure versions address them. After that, we will show how you can use those new functions in your existing code.
Consider the code snippet:
char strTemp; strcpy (strTemp, "Hello");
This will copy the word “Hello” (source string) to the character buffer ‘
strTemp’. A problem with strcpy is that it does not check whether the size of the destination buffer is enough to copy the source string. For instance,
strcpy (strTemp, "Hello world");
will corrupt the memory in adjacent locations to
strTemp, since the buffer
strTemp is only 5 bytes long and the source string is 11 bytes. This weakness is used in buffer overflow exploits to execute an attacker’s code. [Learn more about buffer overflow exploits here.] The safe way to copy strings is to use the strncpy() function that takes the size of the destination buffer also as an argument. Thus, the above case, the function call will be,
strncpy (strTemp, "Hello", 5);
strncpy (strTemp, "Hello world",5);
Now, irrespective of the size of the source string, only 5 bytes will be copied to
strTemp. There are other functions like strcpy() which are also vulnerable to buffer overruns.
Taking one step ahead, Microsoft released a set of more secure versions of these functions in Visual C++ 2005. This enhanced set includes secure versions of functions like strcpy, ctime, fopen, scanf and many more. [See the list of functions here.]
The older functions have now been deprecated and produce a warning when used. The newer functions have the same function name appended by the “_s” suffix. e.g. the secure version for strcpy() is strcpy_s(). Of course, there are differences in function prototypes. In the case of strcpy() and strcpy_s() they are:
char *strcpy( char *strDest, const char *strSrc ); errno_t strcpy_s( char *strDest, size_t nSize, const char *strSrc );
You will notice that strcpy_s() takes size of the destination buffer also, as an input parameter.
While developing new applications, it is a good practice to use the newer versions. For older applications, it is tedious to change the code manually at every place where the older insecure function was called. To make the transition easier, Microsoft provides a feature called ‘secure template overload’. Let’s see the various options provided by ‘secure template overload’.
- The simplest option is to define a symbol _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES. If this symbol is defined as 1, no changes in the code are required; the compiler will automatically replace a call to strcpy to strcpy_s. The size argument will also be provided by the template overload feature itself. So, only one line needs to be added in the existing code.
- If the developers are comfortable with just changing the function names but do not want to provide additional arguments. They can define a symbol as _CRT_SECURE_CPP_OVERLOAD_SECURE_NAMES as 1 and replace all the calls to strcpy by strcpy_s. In this case, template overload feature will provide the extra size argument.
- If the developers do not want to use the secure functions and are ready to go with strcpy only, they can define _CRT_SECURE_NO_DEPRECATE as 1, to suppress the deprecated warning.
Note that the secure template overloads work only in the case of statically defined arrays. For dynamic memory allocation, explicit changes must be made in the code.
Besides the checks on buffer size we discussed above, a number of other features are supported in these enhancements: parameter validation, invalid parameter handler routines, automated null termination of strings, enhanced error reporting etc. You can read its details at http://msdn2.microsoft.com/library/634ca0c2(en-us,vs.80).aspx.
Security Optimized functions, like SecureZeroMemory
When you handle sensitive information like credit card data or passwords, you want to ensure that residues of these do not stay in memory, that these blocks of memory should be cleared after the data is used. The ZeroMemory function is used to fill a block of memory with zeros. Consider the following code fragment, for instance:
char szPasswd; ProcessPassword(szPasswd); // Clear the password from memory ZeroMemory(szPasswd, sizeof(szPasswd));
The above should ideally fill the memory allocated to szPasswd with zeroes. However, there is a problem. Notice that in the above code the contents of szPasswd are not used after the ProcessPassword function returns. So, as part of optimization, the compiler drops the call to ZeroMemory entirely. In this case, the passwords/credit card information will remain in the memory. If that happens, an attacker will be able to steal this information if he can read from the memory. A better option is to use the SecureZeroMemory function, which is a more secure version of ZeroMemory. A call to SecureZeroMemory will not be optimized and memory contents will definitely get cleared. You can read more about SecureZeroMemory
Compiler options to enhance security
Visual C++ has also added two new compiler options to improve security.
- /GS – This is a compiler switch which can be used to detect buffer overruns in the code. It is enabled by default.
- /analyze – This compiler switch can be used to report issues like buffer overrun, memory leaks, null pointer dereferencing etc. This option is not enabled by default.