Chinese Version

Beware the Buffer Overflow

A Spotter's Guide

The phrase "buffer overflow" is almost making it into the mainstream press these days, but many people who write programs which exhibit these mythical beasts are even unaware of what they are or why they are a problem.

#include <string.h>

main() {

    • const char greet[ ] = "hello";
    • char buffer [5];
    • char precious = 7;

      strcpy (buffer, greet);

/*assume precious = 7*/

}

Here's a buffer overflow. The constant array named greet actually contains 6 characters, which strcpy() tries to copy into buffer where there is only room for 5. What will probably happen is that the last character (the invisible '\0' that terminates the string "hello") will be copied into the space formerly known as precious, and the assumption that precious contains the 7 we put into it will be violated.

#include <string.h>

main() {

    • const char greet[5] ="hello";
    • char buffer [6];
    • char precious = 7;
    • strcpy (buffer, greet);
    • memcpy (buffer, great, sizeof buffer);

/*assume precious=7*/

}

Now we've fixed the first problem by making buffer big enough to hold all of greet, the strcpy() is then broken because greet is smaller. "How?" you ask. By making greet into a char array that is not a string, i.e. a char array that has no terminating '\0'. The strcpy() now will not know where to stop, will keep copying until it finds a zero byte, if that ever happens.

The memcpy() is better, because it is guaranteed to stop, but it still does (possibly unquantifiable) Bad Things, as it tries to copy from one byte past the end of greet.

A word of warning: do not assume strncpy() will save you: it is, unfortunately, not simply a bounded version of strcpy(), and has its own set of fangs. Most significantly, unlike all the other str...() functions in the Standard Library, it will not neccessarily give you back a NUL- terminated string even if you give it one to work with. If its source is a long but valid string, and its destination is a shorter buffer, it will fill the buffer with characters from the string but it will NOT terminate that buffer with a '\0'.

The line with gets() might not be a buffer overflow, if the user (or wherever gets() is getting its input from) enters at most 4 characters before a newline; gets() cannot tell that it is not allowed to write past buffer[4]. The line with fgets() can never overflow its buffer. Note, though, that fgets() does not eat the '\n' like gets() does.

#include <stdio.h>

main() {

    • char buffer[5];
    • gets(buffer);
    • fgets(buffer, sizeof buffer, stdin);

}

There are many more possible ways to overflow a buffer, writing data in all sorts of places it was never meant to go. Sometimes the effect might not be noticeable, but you can never be sure. And while the humble string or character array is the most common target, buffer overflows are not type-bigots - they will strike anything they can touch.

To Slay the Monster

When hunting them, the first thing to look for is functions which write into arrays without any way of knowing the amount of space available.

If you get to define the function, you can pass a length parameter in or ensure that every array you ever pass to it is at least as big as the hard-coded maximum amount it will write.

If you are using a function someone else (say, the compiler vendor) has provided then avoiding functions like gets(), which take some amount of data over which you have no control and stuff it into arrays they can never know the size of, is a good start.

Make sure that functions like the str...() family which expect NUL-terminated strings actually get them - store a '\0' in the last element of each array involved just before you call the function, if necessary.

 


 

The 10th Floor, Quantum Plaza, No. 27, Zhichun Road, Haidian District, Beijing, 100083, P.R. China
Tel: +86-10-82357579, 82357580, 82357576

Fax: +86-10-82357574

info@mcu-world.com