|< Day Day Up >|
The ideal way to prevent buffer overflows is for the programmer to follow proper programming practices. These include the following:
How can we prevent buffer overflows in practice? Programmers use the strcpy( ) function to copy a source string to a destination buffer. Unfortunately, the destination array may not be large enough to handle the source string. If your user inputs a very long source string, she will be able to force a buffer overflow on the destination.
To prevent this error, you can specifically check each source string for length before copying it. However, a simpler alternative is strncpy ( ) . This function is similar to strcpy( ) , except that in strncpy( ) only the first n bytes of the source string are copied , which helps to prevent a buffer overflow.
5.5.1 Automated Source-Code Checking
There has never been a programmer born who can code without error 100% of the time. Thus, we now examine automated tools for testing overflow conditions.
Until recently, there has been a paucity of effective tools for automated source code level auditing for buffer overflows. This is because it is horribly difficult to take into account all of the possible errors inherent in a program that is thousands of lines long.
One commercial example is PolySpace (http://www.polyspace.com), which has come up with a tool to detect buffer overflows in ANSI C applications at compilation time. While the Viewer module currently can be run on Windows, the Verifier itself requires a Linux box to run. Windows-only programmers will have to break down and install a dedicated Linux box to run PolySpace as a batch tool; the results can then be explored under Windows. If you currently do not run Linux, we recommend doing so immediately; a true security expert should be able to move between Windows and Linux with ease. However, for those who are completely Linophobic, PolySpace has started porting the Verifier engine to Windows.
5.5.2 Compiler Add-Ons
Linux provides various compiler add-ons and libraries that perform runtime bounds checking in C/C++. StackGuard (http://immunix.org) is one example. StackGuard detects stack smashing attacks by protecting the return address on the stack from being altered . It places a " canary " word next to the return address when a function is called. If a buffer overflow is attempted, StackGuard detects that the canary word has been altered when the function returns. If this happens, the StackGuarded program logs an adminstrator alert and terminates.
StackGuard is implemented as a small patch to the gcc code generator in the function_prolog() and function_epilog( ) routines. StackGuard utilizes function_prolog( ) to insert canaries on the stack when functions start, then uses function_epilog( ) to check canary integrity when the functions exit. It can thus detect any attempt at corrupting the return address before the function returns.
Another useful program from immunix.org is FormatGuard, which guards against format bug exploits. FormatGuard uses the ability of C++ to distinguish macros with identical names but a different number of arguments. FormatGuard provides a macro definition of the printf function for each of anywhere from 1 to 100 arguments. Each of these macros in turn calls a safe wrapper that counts the number of % characters in the format string and rejects the call if the number of arguments does not match the number of % directives.
In order for an application to be protected with FormatGuard, the application needs to be recompiled against the FormatGuard glibc headers. FormatGuard is a wrapper around the following libc calls: syslog( ) , printf( ) , fprintf( ) , sprintf( ) , snprintf ( ) .
5.5.3 Miscellaneous Protection Methods
Another way to prevent buffer overflows is to make the stack and data memory nonexecutable. This is not a complete solution, as it still allows the attacker to make the code jump into unexpected positions . However, it does make exploits more difficult to execute. This solution is available in Linux in the form of a patch.
Automatic bounds-checking tools can add another layer of protection to the above techniques. Unlike C++, Perl and Java provide innate bounds checking, saving the programmer from extensive security coding. However, automatic bounds checking can also be provided for C++ using tools under various operating systems. Examples of such tools include BOWall, Compuware's Boundschecker, and Rational's Purify.
|< Day Day Up >|