I'm trying to make glibc detect stack smashing, and I use the following code:
#include <stdio.h>
#include <string.h>
static const int n = 5;
int main(int argc, char *argv[])
{
if (argc != 2)
{
printf("usage: %s string\n", argv[0]);
return -1;
}
printf("%s, len = %d\n", argv[1], strlen(argv[1]));
unsigned char a[n][n];
unsigned char * b = a[n - 1];
memcpy(b, argv[1], (strlen(argv[1]) + 1) * sizeof(unsigned char));
return 0;
}
If argv[1] length greater than 5, I expect detection of stack smashing error, however, I do not, and valgrind detects no errors. What I should change to get this error? (array a must be two-dimensional)
It seems like the logic in gcc which decides when to enable stack protection is slightly tricky. First note from the docs:
-fstack-protector
Emit extra code to check for buffer overflows, such as stack smashing attacks. This is done by adding a guard variable to functions with vulnerable objects. This includes functions that call alloca, and functions with buffers larger than 8 bytes. The guards are initialized when a function is entered and then checked when the function exits. If a guard check fails, an error message is printed and the program exits
So, we should expect a function with local buffers smaller than 8 bytes to be unprotected. For example, this:
int unprotected() {
char a[5];
strcpy(a, "this is much too long");
return a[0];
}
compiled with gcc -fstack-protector -Wstack-protector
, gives a warning like
warning: stack protector not protecting function: all local arrays are less than 8 bytes long [-Wstack-protector]
So, you might think your char[5][5]
will be protected, since it is more than 8 bytes long. However, when I compile that to assembler, I get no warning or stack protection (you can find the assembler to look for in this Dr. Dobbs article). It seems that gcc treats it as 5 buffers of 5 bytes each instead of a single buffer of 25 bytes.
You can persuade gcc to enable stack protection either by showing it a single buffer larger than 8 bytes:
void protected(char *arg) {
union {
char dummy[5 * 5];
char a[5][5];
} u;
memcpy(u.a[4], arg, (strlen(arg) + 1));
}
or by simply using -fstack-protector-all
.