Author Archive

Getting Around Conditionally Banned APIs When Using Microsoft’s banned.h Header File

December 8th, 2009 by

This code sample makes use of banned.h, a Microsoft-supplied header file that deprecates dangerous CRT functions. Microsoft also poisons these functions on UNIX if you include banned.h there. This is a Good Thing, but what about the fact that they banned strlen? The banned API page states:

For critical functions, such as those accepting anonymous Internet connections, strlen must also be replaced.

That’s good advice for cases where you want to operate on untrusted data. In those cases they tell you that you should use strnlen_s. The problem is, banned.h straight out bans strlen. There is no way to tell it that hey, this particular invocation is safe because I control the buffer in all aspects. Nope, sorry. You can’t use strlen. Or can you?

Here is a code sample that uses banned.h to deprecate unsafe APIs, yet still manages to invoke strlen when necessary. The sample works in both Visual Studio on Windows and GCC on UNIX.

 
//
 
//  banned_test.c
//  20091208 ramsey@casabasecurity.com
//
//  A sample program that illustrates how to "grandfather in" banned APIs
//  for use when they are marked deprecated (Windows) or poisoned (UNIX)
//  by the compiler.
//
//  to compile on Windows:
//  cl /GS /W4 /WX banned_test.c
//
//  to compile on UNIX:
//  gcc -Wall -Werror banned_test.c
 
#if defined _WIN32
 
#include <windows.h>
#endif    // _WIN32
 
#include <stdio.h>
#include <string.h>
#if defined _WIN32
 
size_t my_strlen(const char *string)
{
  size_t len;
  #pragma warning(push)
  #pragma warning(disable:4995)
  len = strlen(string);
  #pragma warning(pop)
  return len;
}
 
#else
#define my_strlen strlen
#endif    // _WIN32
 
#include "banned.h"
 
int main(int ac, char **av)
{
  char *str = "foo";
  #if defined _WIN32
  UNREFERENCED_PARAMETER(ac);
  UNREFERENCED_PARAMETER(av);
  #endif    // _WIN32
  #if defined _WIN32
  (void)printf("len is %Id\n", strlen(str));
  #else
  (void)printf("len is %zd\n", strlen(str));
  #endif    // _WIN32
  return 0;
}

Note that this code requires the use of Microsoft’s banned.h header file, which can be downloaded here. Stick it in the same directory as the above source file.

To compile the sample in Windows from a Visual Studio Command Prompt:


cl banned_test.c /GS /W4 /WX

As expected, this program will generate an error when run:


banned_test.c

banned_test.c(50) : error C2220: warning treated as error - no 'object' file generated

banned_test.c(50) : warning C4995: 'strlen': name was marked as #pragma deprecated

Now edit banned_test.c and change the strlen on line 50 to my_strlen and recompile:


cl banned_test.c /GS /W4 /WX

It should compile without error. Now run it and you should see:


len is 3

Nifty.

The same code works without change on UNIX (tested on NetBSD):


gcc -Wall -Werror banned_test.c

As with the Windows example, running the program will generate an error, as expected:


banned_test.c:52:31: error: attempt to use poisoned "strlen"

Again, change the occurrence of strlen (this time on line 52) to my_strlen and recompile. It will work and when run, it will say:


len is 3

What’s going on here is simple. While we are banning use of the strlen function, we are still allowing its use selectively through a wrapper that we have “grandfathered in.” This is easy to accomplish in UNIX: we simply

#define my_strlen strlen

prior to including banned.h and use that function call entry point instead. Problem solved. This is not as easy to accomplish with Windows, however, as cl.exe has no notion of “grandfathering in” deprecated APIs. So what we do is wrap strlen in another function. We ignore the deprecation warning that occurs where we make the call to strlen through the judicious application of some Visual Studio-specific pragma instructions. Now all need to do is call in to our new function entry point. We’re good to go. The Windows solution requires a little more work up front, but turns out to be not so hard to accomplish after all.

On the Importance of Good Developer Documentation

November 20th, 2009 by

Programmers rely on documentation. It's how we learn to use APIs. Misusing APIs is a leading source of vulnerability. You might think that documentation is a cure to this ailment. Unfortunately, as someone who has been in software development for a long time, I can tell you that documentation quality is not always what it should be. API documentation serves as a reference. I have yet to meet the programmer who can recall every nuance about every API for all the languages they program in. (Were such a programmer to exist, its name might well be Robby the Robot.)

Recently I was converting strings using the mbstowcs_s and wcstombs_s functions. (These are from from the bounds checking extensions to the C Library specified in ISO/IEC TR 24731-1.) These functions allow you to convert multibyte character sequences to and from wide character sequences. These functions are available to C and C++ programmers using Microsoft's Visual Studio compiler. (I am not yet aware of any UNIX compatible compiler that supports the draft TR 24731-1 standard.)

Since these two functions convert strings, it is worth looking at the parameters they expect. (Not doing so is a sure fire way to do something stupid, like enable a buffer overflow.) Looking at the relevant parameters for these two functions, we see:

mbstowcs_s:
[in] sizeInWords
      The size of the wcstr buffer in words.
[in] count
      The maximum number of wide characters to store in the wcstr buffer, not including the terminating null, or _TRUNCATE.

wcstombs_s:
[in] sizeInBytes
      The size in bytes of the mbstr buffer.
[in] count
      The maximum number of bytes to be stored in the mbstr buffer, or _TRUNCATE.

Does count in wcstombs_s account for the terminating NULL or not? Failure to account for this could introduce an off-by-one error which, in turn, may lead to an exploitable condition, such as a buffer overflow. How can we determine this from the documentation? Well, in its current state, we can't. This is what we call a “doc bug.”

Luckily, Microsoft includes the source code for the C Runtime with most Visual Studio SKUs. Assuming you installed Visual Studio in Program Files, you should be able to find the CRT source code in Program Files\Microsoft Visual Studio 9.0\VC\crt\src. CRT source code is included with all Visual Studio SKUs except for the Express Editions. Luckily for Express Edition users, the forthcoming Visual Studio 2010 release finally opens up the CRT sources to Express Edition users. If you are using an Express Edition of VS2008 or earlier, consider grabbing the VS2010 Express beta from here.

In any case, if you have the CRT source code, it is easy to track down the source for wcstombs_s and check to see if the terminating NULL is intended to be accounted for or not. Looking into wcstombs.c we discover this bit of text in the comment for the wcstombs_s function:

size_t n = maximum number of bytes to store in s (not including the terminating NULL)

Clearly, the terminating NULL is not meant to be included. This is as we suspected, but now we have verified it instead of blindly assuming that it would be the case. As security practitioners we should be careful not to make assumptions. Verify instead!

This documentation bug has been reported to Microsoft. With any luck it will get addressed prior to the VS 2010 release on March 22, 2010.

Use the Source, Luke!

October 20th, 2009 by

If there's one thing that I've learned throughout the years as a programmer, it is not always safe to trust the documentation. In fact, there is an old saying, “Use the source, Luke!” When possible, you should do just that.

While looking over the CERT Secure C Coding Standard I noticed the following recommendation: ERR30-C. Set errno to zero before calling a library function known to set errno, and check errno only after the function returns a value indicating failure. CERT goes on to write, “[s]ome functions lack documentation regarding errno in the C99 standard.” They follow this up with an example for Windows: “[i]n this compliant solution, errno is not checked because fopen() makes no promise of setting it.” This would be fine, were it true. However, it is false. Let us take a closer look.

It is true that the symbol, errno, appears nowhere in the MSDN documentation for fopen. However, one need only look to fopen.c (included with all commercial Visual C implementations) to see that errno.h is #include'd and errno is indeed set for locked streams, bad names (e.g., empty string), et al.

The use of errno is not as robust in the case of Microsoft's fopen implementation as it is in the implementation on my NetBSD box, but that's not the point. The point is that CERT stated something was true based on documentation when in fact, it was not true. The lesson here is that one cannot simply rely on assumptions based on documentation, one must also look to the source to see what is happening.

In the case of Microsoft's C and secure C runtimes, the source code is available for you to look at, provided you have Visual Studio installed. (Caveat: you don't get the CRT source code if you install Visual C++ Express.) I found the code living on my box under Program Files at Microsoft Visual Studio 9.0\VC\crt\src.

Of course, if you're programming on Windows you should prefer fopen_s to fopen anyway. For the record, the MSDN documentation for fopen_s clearly states that it returns an errno_t, which is the Secure CRT's answer to errno.

Update: I just found out from a source inside the Visual Studio team at Microsoft that Visual Studio 2010 Beta 2's Express Edition SKU contains the CRT source code. That's good news. You can get more information on Visual Studio 2010 Beta 2 here, and you can download it here.

A Vim plugin for highlighting APIs banned by the Microsoft SDL

August 23rd, 2009 by

I do a lot of programming, so I live in my editor. I use Vim. If you also use Vim then I've got something to share with you: a new syntax plugin that highlights function calls banned by Microsoft's Security Development Lifecycle (SDL). You can obtain the banned.vim syntax plugin from the Vim script archive.

The banned.vim syntax plugin will highlight C function calls that have been banned by the SDL. It adds functionality to the existing C and C++ Vim syntax plugins. Banned APIs, such as strcpy and others, will appear visually in Vim as if they were errors. It is my hope that this extra attention will cause you to reconsider using the banned API and replace it instead with a safer alternative. Although many of these banned function calls are Windows-specific, there are quite a few that are also available in UNIX and should be avoided. Details on the APIs banned by Microsoft's SDL can be found on Microsoft's site.

Here's a screen shot of banned.vim in action. In this case we're editing str_cat.c, one of the entries from the 2008 SANS Awards for Finding Coding Books with Secure programming Flaws. Notice the banned APIs in the code below?

banned.vim in action

Installing banned.vim is easy. First, you need to know what your runtimepath is, which varies from operating system to operating system. If you don't know what your runtimepath is, check the Vim documentation. Second, create the directory structure after/syntax in your runtimepath directory if it doesn't already exist. Third, copy banned.vim into runtimepath/after/syntax as both c.vim and cpp.vim. That's all there is to installation. There is no need to edit your .vimrc or anything.

I would like to thank Rob Mooney for suggesting this plugin in the first place.