|
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.

|