Low-Hanging Fruit

Low-Hanging Fruit

One of the first things to try is to look for known unsafe functions; a good list of these is found in Chapter Appendix A, Dangerous APIs. In particular, the string-handling functions need careful examination, even if the calls are from the safe libraries. Recall that the off-by-one example in Chapter 5, Public Enemy #1: the Buffer Overrun, used strncpy, not strcpy. Examine each of these and ask whether the input pointers might be NULL, whether the input strings could be missing a terminating null character, and whether the caller might have gotten the length arguments wrong. Next, look for off-by-one errors; these are among the most common when people are attempting to use safe string handlers. If the classic counted string functions are used, look for a null termination immediately after the function strncpy, strncat, and snprintf aren't guaranteed to null-terminate. Likewise, look for truncation errors. The traditional safe functions can make it difficult to determine whether an input string was truncated.

Buffers of any type need to be checked carefully; bounds checking must be enforced on any access to an array. Exploits can be built out of overflows of any type, not just strings. Hopefully, the examples in Chapter 5 have shown that heap overflows are just as dangerous as stack-based buffer overruns. An additional problem with heaps one that you won't see with other types of overflows is that freeing memory twice can lead to an exploitable condition. Under the right circumstances, freeing memory twice will lead to execution of arbitrary code, not just a program crash. Likewise, failure to free allocated memory can sometimes be used by an attacker in a denial of service attack. Use of _alloca needs to be checked carefully if an attacker can cause you to allocate a very large buffer on the stack, your application could run out of stack space and crash. I would tend to discourage use of _alloca in general; using it in a recursive function is extremely dangerous.

If your application deals with mixed Unicode and ANSI character sets, be extremely careful when dealing with conversion functions. For example, WideCharToMultiByte is defined as follows:

int WideCharToMultiByte( UINT CodePage, //code page DWORD dwFlags, //performance and mapping flags LPCWSTR lpWideCharStr, //wide-character string int cchWideChar, //number of chars in string LPSTR lpMultiByteStr, //buffer for new string int cbMultiByte, //size of buffer LPCSTR lpDefaultChar, //default for unmappable chars LPBOOL lpUsedDefaultChar //set when default char used );

The fourth parameter is the number of wide characters in the input string, but the size of the output buffer is the number of bytes. MultiByteToWideChar behaves similarly. Although this may seem unnecessarily confusing, remember that the output might be a multibyte character set, not ANSI. Another good example of an API set where buffers are sometimes defined by the number of bytes and sometimes by the number of wide characters is the C++ DCOM interface for administering IIS (Internet Information Services). If you look closely, the calls that require a number of bytes can return binary data, but it can be tricky. Another point to consider is that the author of the code (or even the documentation) might not have used Hungarian notation correctly check the variable type as declared.

Another potential problem that's worth mentioning is the use of TCHAR. A TCHAR is either a char or WCHAR type, depending on whether there's a #define UNICODE for that source file. I've seen a number of bugs that resulted from not being certain whether a buffer was single-byte or double-byte. I prefer to always explicitly use the character type I want.



Writing Secure Code
Writing Secure Code, Second Edition
ISBN: 0735617228
EAN: 2147483647
Year: 2001
Pages: 286

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net