Hello,
It's nice to see a more security-minded release of gcc with v4.
Variables are moved around to reduce chances for exploitation,
-fstack-protector, etc. Great!
Why are local variables once-again adjacent to the saved frame pointer
though? gcc v 2 called and wants one of its "features" back.
func(char *b){
char buf[512];
if( strlen(b) > sizeof buf) return;
strcpy(buf, b);
}
0x080483a7 <func+3>: sub $0x208,%esp
0x080483ad <func+9>: mov 0x8(%ebp),%eax
0x080483b0 <func+12>: mov %eax,0x4(%esp)
0x080483b4 <func+16>: lea 0xfffffe00(%ebp),%eax
0x080483ba <func+22>: mov %eax,(%esp)
0x080483bd <func+25>: call 0x80482e8 <[EMAIL PROTECTED]>
0x080483c2 <func+30>: leave
0x080483c3 <func+31>: ret
0x208 = 520 bytes; alright padding can be useful
0xfffffe00(%ebp) = -512 + ebp.
OOPS! In effect the padding is no longer in between the saved frame
pointer and the local vars.
I've seen this in various versions of gcc 4.
Gcc 3 would have placed this padding between the saved frame pointer
and the local vars. Here's the result from gcc 3.4:
0x08048367 <func+3>: sub $0x218,%esp
...
0x08048374 <func+16>: lea 0xfffffdf8(%ebp),%eax
Thats -520+ebp. It also takes a little bit more padding.
Any good reason NOT to pad between the local vars and control data?
P.S. check out this cute rendition from gcc 4.1.1:
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]){
char buf[512];
if(strlen(argv[1]) <= sizeof buf) strcpy(buf, argv[1]);
}
Dump of assembler code for function main:
0x080483a4 <main+0>: lea 0x4(%esp),%ecx
0x080483a8 <main+4>: and $0xfffffff0,%esp
0x080483ab <main+7>: pushl 0xfffffffc(%ecx)
0x080483ae <main+10>: push %ebp
0x080483af <main+11>: mov %esp,%ebp
0x080483b1 <main+13>: push %edi
0x080483b2 <main+14>: push %ecx
0x080483b3 <main+15>: sub $0x210,%esp
0x080483b9 <main+21>: mov %ecx,0xfffffdf4(%ebp)
0x080483bf <main+27>: mov 0xfffffdf4(%ebp),%edx
0x080483c5 <main+33>: mov 0x4(%edx),%eax
0x080483c8 <main+36>: add $0x4,%eax
0x080483cb <main+39>: mov (%eax),%eax
0x080483cd <main+41>: mov $0xffffffff,%ecx
0x080483d2 <main+46>: mov %eax,0xfffffdf0(%ebp)
0x080483d8 <main+52>: mov $0x0,%al
0x080483da <main+54>: cld
0x080483db <main+55>: mov 0xfffffdf0(%ebp),%edi
0x080483e1 <main+61>: repnz scas %es:(%edi),%al
0x080483e3 <main+63>: mov %ecx,%eax
0x080483e5 <main+65>: not %eax
0x080483e7 <main+67>: dec %eax
0x080483e8 <main+68>: cmp $0x200,%eax
0x080483ed <main+73>: ja 0x804840f <main+107>
0x080483ef <main+75>: mov 0xfffffdf4(%ebp),%edx
0x080483f5 <main+81>: mov 0x4(%edx),%eax
0x080483f8 <main+84>: add $0x4,%eax
0x080483fb <main+87>: mov (%eax),%eax
0x080483fd <main+89>: mov %eax,0x4(%esp)
0x08048401 <main+93>: lea 0xfffffdf8(%ebp),%eax
0x08048407 <main+99>: mov %eax,(%esp)
0x0804840a <main+102>: call 0x80482e8 <[EMAIL PROTECTED]>
0x0804840f <main+107>: add $0x210,%esp
0x08048415 <main+113>: pop %ecx <----immediate control
0x08048416 <main+114>: pop %edi |
0x08048417 <main+115>: pop %ebp V
0x08048418 <main+116>: lea 0xfffffffc(%ecx),%esp
0x0804841b <main+119>: ret
0x0804841c <main+120>: nop
esp can be controlled controlled right away before the "ret"
instruction. This new prologue/epilogue opened up a fun new
possibility for an off-by-one in main().
One final question, what is the purpose of this new prologue and
epilogue for main?
Why re-align the stack and push the saved ret to a new place [pushl
0xfffffffc(%ecx)] if you're going to just use the old one anyway [
lea 0xfffffffc(%ecx),%esp] ???
have phuN!