Question

Since there is an option -fstack-protector-strong in gcc to detect stack smashing. However, it can not always detect stack buffer overflow. For the first function func, when I input a 10 char more string, the program does not always crash. My question is where there is a way to detect stack buffer overflow.

void func()
{
    char array[10];
    gets(array);
}

void func2()
{
    char buffer[10];
    int n = sprintf(buffer, "%s", "abcdefghpapeas");
    printf("aaaa [%d], [%s]\n", n, buffer);
}

int main ()
{
   func();
   func2();
}
Was it helpful?

Solution

Overflows on the stack are either hard to detect or very expensive to detect - chose your poison.

In a nutshell, when you have this:

 char a,b;
 char *ptr=&a;
 ptr[1] = 0;

then this is technically legal: There is space allocated on the stack which belongs to the function. It's just very dangerous.

So the solution might be to add a gap between a and b and fill that with a pattern. But, well, some people actually write code as above. So your compiler needs to detect that.

Alternatively, we could create a bit-map of all bytes that your code has really allocated and then instrument all the code to check against this map. Very safe, pretty slow, bloats your memory usage. On the positive side, there are tools to help with this (like Valgrind).

See where I'm going?

Conclusion: In C, there is no good way to automatically detect many memory problems because the language and the API is often too sloppy. The solution is to move code into helper functions that check their parameters rigorously, always to the right thing and have good unit test coverage.

Always use snprintf() versions of functions if you have a choice. If old code uses the unsafe versions, change it.

OTHER TIPS

You can use a tool called Valgrind

http://valgrind.org/

My question is where there is a way to detect stack buffer overflow...

void func()
{
    char array[10];
    gets(array);
}

void func2()
{
    char buffer[10];
    int n = sprintf(buffer, "%s", "abcdefghpapeas");
    printf("aaaa [%d], [%s]\n", n, buffer);
}

Because you are using GCC, you can use FORTIFY_SOURCES.

FORTIFY_SOURCE uses "safer" variants of high risk functions like memcpy, strcpy and gets. The compiler uses the safer variants when it can deduce the destination buffer size. If the copy would exceed the destination buffer size, then the program calls abort(). If the compiler cannot deduce the destination buffer size, then the "safer" variants are not used.

To disable FORTIFY_SOURCE for testing, you should compile the program with -U_FORTIFY_SOURCE or -D_FORTIFY_SOURCE=0.


The C Standard has "safer" functions via ISO/IEC TR 24731-1, Bounds Checking Interfaces. On conforming platforms, you can simply call gets_s and sprintf_s. They offer consistent behavior (like always ensuring a string is NULL terminated) and consistent return values (like 0 on success or an errno_t).

Unfortunately, gcc and glibc does not conform to the C Standard. Ulrich Drepper (one of the glibc maintainers) called bounds checking interfaces "horribly inefficient BSD crap", and they were never added. Hopefully it will change in the future.

First of all Do Not Use gets. By now almost everyone knows the all the security and reliability problems that can occur with gets. But it's included here for historical reasons as well because it's a very good example of bad programming.

Let's look at all the problems with the code:

// Really bad code
char line[100];
gets(line);

Because gets does not do bounds checking a string longer than 100 characters will overwrite memory. If you're lucky the program will just crash Or it might exhibit strange behavior.

The gets function is so bad that the GNU gcc linker issues a warning whenever it's used.

/tmp/ccI5WJ5m.o(.text+0x24): In function `main':
: warning: the `gets' function is dangerous and should not be used.

Protect array accesses with assert

C/C++ does not do bound checking.

for example:

int data[10]

i = 20
data[20] = 100 //Memory Corruption

Use the assert function for above code

#include<assert.h>


int data[10];
i=20

assert((i >= 0) && (i < sizeof(data) / sizeof(data[0]))); // throws 

data[i] = 100

Array overflows are one of the most common programming errors and are extremely frustrating to try and locate. This code doesn't eliminate them, but it does cause buggy code to abort early in a way that makes the problem tremendously easier to find.

And use snprintf(buffer, sizeof(buffer), "%s", "abcdefghpapeas") and some tools like valgrind or GDB.

Hope this helps you..

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top