sil2100//vx developer log

Welcome to my personal web page

Stackguard in gcc

During programming in C for work yesterday, I popped into a small issue I did not expect. I was concerned because a piece of code that I normally thought would work (and it did, but in other circumstances) - this time did not. I wanted to better understand this problem and in the end learned a bit about the Stackguard in gcc. Some of you probably heard about it already. Consider the following piece of code below.

2011-04-27 14:42


#include <stdio.h>
#include <string.h>

struct data {
    char stuff[2];
    char more[510];

int main(void)
    struct data foo;
    strcpy((char *)foo.more, "Something bigger than 2 bytes long");

    return 0;

When compiled with the standard gcc test.c -o test line, the program will probably work normally. Yes, stuff is only 2 bytes long, but afterwards we still have 510 more bytes available, so everything is fine - there's plenty of space. We can even add __attribute__ ((__packed__)) to make sure of that.
But then, let's try compiling the same code with optimization. On my compiler version (4.4.3-4ubuntu5), even building with -O1 and bigger suddenly made this code detect an buffer overflow during compilation and during runtime - which is understandable, of course. But why now? The warning informs of some __builtin___strcpy_chk() being called. In disassembly we see that indeed instead of the standard strcpy() we wanted, a different, safe version of the function is called. In libssp/strcpy-chk.c of the gcc 4.3.3 source code we can see the internals of __strcpy_chk(). This version is called instead in cases when a statical, known sized buffer is used. It first checks if the copied string can fit in the destination buffer, and bails out when not. Such mechanisms are part of the GNU C compiler's Stackguard - you can read a bit more about it here.

Why during optimization? It seems that the Ubuntu version of gcc, even the basic optimization levels have the _FORTIFY_SOURCE define set to 2 by default. This can be disabled by adding a -D_FORTIFY_SOURCE=0 to our gcc flags during compilation when needed. Then we can finally do what all we want with our static buffers. At least almost!