Strsafe.h: Safer String Handling in C

 

Michael Howard
Secure Windows Initiative
Microsoft Corporation

June 2002

Summary: Keep your C code secure with strsafe.h functions, a set of safer string handling functions for the C programming language. (3 printed pages)

During the Microsoft® Windows® Security Push, a group of testers, program managers, and programmers decided to define and create a set of safer string handling functions for the C programming language. The aim was to provide a set of functions that could be used by Windows developers and developers across Microsoft.

Simply put, the existing C-runtime functions are not good enough in light of today's hostile environment. The current functions have inconsistent return values and parameters, truncation errors, and lack advanced functionality. Frankly, it is too easy to write code with buffer overruns when using the existing functions.

We found that for C++ developers there are plenty of classes available in MFC (CString), ATL (CComBSTR), STL (string), and other class libraries that do string manipulation well. However, a lot of C code still exists today, and many people use C++ as a 'better C' and do not use classes.

Enter strsafe (see Using the Strsafe.h Functions), made up of a header file and an optional library, included with newer versions of the Platform SDK. All you need to do to your source code is add one line:

#include "strsafe.h"

And go!

Remember, using the library implementation is optional.

The main requirements when designing strsafe were:

  • Always NULL-terminate the string.
  • Always take a destination buffer size.
  • Always return consistent return codes (an HRESULT).
  • Support 32-bit and 64-bit environments.
  • Flexibility.

We feel it is a lack of uniformity that makes many existing C runtime string-handling functions susceptible to security errors, and the extra consistency in strsafe should help remedy the problem. Note that strsafe is not a panacea. Simply using the new functions will not make your code secure and robust—you must still engage your brain—but it will help!

Here's some example C code using the current C runtime functions:

void UnsafeFunc(LPTSTR szPath,DWORD cchPath) {
   TCHAR szCWD[MAX_PATH];

   GetCurrentDirectory(ARRAYSIZE(szCWD), szCWD);
   strncpy(szPath, szCWD, cchPath);
   strncat(szPath, TEXT("\\"), cchPath);
   strncat(szPath, TEXT("desktop.ini"),cchPath);
}

This code is riddled with bugs—no return values are checked, cchPath is incorrectly used in the calls to strncat (its maximum value should be how much space is left in the target buffer, not the total size of the buffer), and it's a buffer overrun waiting to happen. Yet this kind of code is very common.

The same code using strsafe is:

bool SaferFunc(LPTSTR szPath,DWORD cchPath) {
   TCHAR szCWD[MAX_PATH];

   if (GetCurrentDirectory(ARRAYSIZE(szCWD), szCWD)            &&
      SUCCEEDED(StringCchCopy(szPath, cchPath, szCWD))     &&
      SUCCEEDED(StringCchCat(szPath, cchPath, TEXT("\\"))) &&
      SUCCEEDED(StringCchCat(szPath, cchPath, TEXT("desktop.ini")))) {
         return true;
   }

   return false;
}

This code checks all return values, and always passes in the same target buffer size. You can also use the Ex versions of the strsafe functions if you require greater functionality such as:

  • You want to know the current target buffer end.
  • You want to know the amount of space left in the target buffer.
  • You want to fill the empty buffer space with a specific character.
  • You want to fill the string with a specific value if the string handling function fails.
  • You want to set the target buffer to NULL on failure.

So what about performance? The good news is, you'll probably notice no performance difference in your code. I ran a mixture C runtime string concatenation functions, a mixture of strsafe functions, and a mixture of strsafe Ex functions ten million times (that's right, 10,000,000 times) on my 1.8GHz computer and came up with the following statistics:

  • C Runtime—7.3 seconds
  • Strsafe—8.3 seconds
  • Strsafe (Ex)—11.1 seconds

For this test, the Ex versions of the strsafe functions set NULL on failure and 0xFE as the fill byte:

DWORD dwFlags = STRSAFE_NULL_ON_FAILURE | STRSAFE_FILL_BYTE(0xFE);

Setting the fill byte is time consuming; in fact, if the flags are only set to NULL on failure, the time taken is the same as the non-Ex strsafe functions.

The performance impact isn't big. I doubt you have much code that calls a huge mixture of string manipulation functions millions of times.

Also be aware that by default, strsafe will #undef all the C runtime string handling functions and the error will inform you which strsafe function to use as a replacement.

So check out Using the Strsafe.h Functions and enjoy.

Michael Howard is a Security Program Manager in the Secure Windows Initiative group at Microsoft. He is also the coauthor of Writing Secure Code and the main author of Designing Secure Web-based Applications for Microsoft Windows 2000. His main focus in life is making sure people design, build, test, and document nothing short of a secure system. His favorite line is "One person's feature is another's exploit."