Im doing some research on buffer overflows and I was wondering how does stack smashing protection works
i have this code:
int main( )
{
char Buf[16];
printf(“Digite o seu nome: ”);
gets(Buf);
printf(“%s”,Buf);
return 0;
}
I compile it with gcc
and then i put in a bunch of chars to fill the buffer
First i put 16 chars
$ ./Exemplo1
Digite o seu nome: AAAAAAAAAAAAAAAA
Ola AAAAAAAAAAAAAAAA
This is ok because the buffer is the right size
Next i try 24 chars
$ ./Exemplo1
Digite o seu nome: AAAAAAAAAAAAAAAAAAAAAAAA
Ola AAAAAAAAAAAAAAAAAAAAAAAA
Why does it still works?
shouldn’t this cause the program to terminate!?
It only terminates the program when I put 25 or more chars
./Exemplo1
Digite o seu nome: AAAAAAAAAAAAAAAAAAAAAAAAA
Ola AAAAAAAAAAAAAAAAAAAAAAAAA
* stack smashing detected *: ./Exemplo1 terminated
Why? what’s after the buffer that is not the return address?
What I read about and what I think understand is that it should have a canary value, but its supposed to terminate the program if that value has changed and with 24 chars written to the buffer shouldn’t it still give me a stack smashing detected even if the return address hasn’t changed but the canary value did.
Thanks.
From my brief reading of the generated assembly, here is what I think happens (gcc 4.4.5 on 64-bit Ubuntu).
The canary is a double word (8 bytes). The stack — including the canary — grows in increments of 16 bytes. The canary is placed right at the end of the stack frame. To satisfy all three requirements at the same time,
gccmay need to insert padding between your automatic variables and the canary.Since in your code
Bufis 16 bytes long,gccplaces 8 bytes of padding betweenBufand the canary (needed in order to make the size of the stack frame a multiple of 16 bytes). This explains why you can enter up to 24 chars without triggering the stack smashing detection.If I change
Bufto be 8 bytes long, there’s no longer need for any padding, and entering 9 chars triggers the protection:Obviously, this is dependent on the compiler, hardware platform, compiler flags etc.
It also goes without saying that one shouldn’t expect this mechanism to be bullet-proof.
If you’d like to experiment further, try compiling your code with different buffer sizes and with/without
-fno-stack-protector. If you use-Sto generate assembly code, you’ll be able to see how the generated code changes as you tweak the settings.