tags:

views:

120

answers:

3

I have the following C application:

#include <stdio.h>

void smash()
{
    int i;
    char buffer[16];
    for(i = 0; i < 17; i++)  // <-- exceeds the limit of the buffer
    {
        buffer[i] = i;
    }
}

int main()
{
    printf("Starting\n");
    smash();
    return 0;
}

I cross-compiled using the following version of gcc:

armv5l-linux-gnueabi-gcc -v
Using built-in specs.
Target: armv5l-linux-gnueabi
Configured with: /home/tarjeif/svn/builder/build_armv5l-linux-gnueabi/gcc-4.4.1/gcc-4.4.1/configure --target=armv5l-linux-gnueabi --host=i486-linux-gnu --build=i486-linux-gnu --prefix=/home/tarjeif/svn/builder/build_armv5l-linux-gnueabi/toolchain --with-sysroot=/home/tarjeif/svn/builder/build_armv5l-linux-gnueabi/toolchain --with-headers=/home/tarjeif/svn/builder/build_armv5l-linux-gnueabi/toolchain/include --enable-languages=c,c++ --with-gmp=/home/tarjeif/svn/builder/build_armv5l-linux-gnueabi/gmp-5.0.0/gmp-host-install --with-mpfr=/home/tarjeif/svn/builder/build_armv5l-linux-gnueabi/mpfr-2.4.2/mpfr-host-install --disable-nls --disable-libgcj --disable-libmudflap --disable-libssp --disable-libgomp --enable-checking=release --with-system-zlib --with-arch=armv5t --with-gnu-as --with-gnu-ld --enable-shared --enable-symvers=gnu --enable-__cxa_atexit --disable-nls --without-fp --enable-threads
Thread model: posix
gcc version 4.4.1 (GCC) 

Invoked like this:

armv5l-linux-gnueabi-gcc -ggdb3 -fstack-protector-all -O0 test.c

When run on target, it outputs:

Starting
*** stack smashing detected ***: ./a.out terminated
Aborted (core dumped)

I load the resulting core dump in gdb yielding the following backtrace:

GNU gdb (GDB) 7.0.1
Copyright (C) 2009 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html&gt;
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "--host=i486-linux-gnu --target=armv5l-linux-gnueabi".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/&gt;...
Reading symbols from /home/andersn/workspace/stacktest/a.out...done.
Reading symbols from /home/andersn/workspace/stacktest/linux/toolchain/lib/libc.so.6...done.
Loaded symbols for /home/andersn/workspace/stacktest/linux/toolchain/lib/libc.so.6
Reading symbols from /home/andersn/workspace/stacktest/linux/toolchain/lib/ld-linux.so.3...done.
Loaded symbols for /home/andersn/workspace/stacktest/linux/toolchain/lib/ld-linux.so.3
Reading symbols from /home/andersn/workspace/stacktest/linux/toolchain    /lib/libgcc_s.so.1...done.
Loaded symbols for /home/andersn/workspace/stacktest/linux/toolchain/lib/libgcc_s.so.1
Core was generated by `./a.out'.
Program terminated with signal 6, Aborted.
#0  0x40052d4c in *__GI_raise (sig=6) at ../nptl/sysdeps/unix/sysv/linux/raise.c:67
67  ../nptl/sysdeps/unix/sysv/linux/raise.c: No such file or directory.
    in ../nptl/sysdeps/unix/sysv/linux/raise.c
(gdb) bt
#0  0x40052d4c in *__GI_raise (sig=6) at ../nptl/sysdeps/unix/sysv/linux/raise.c:67
#1  0x40054244 in *__GI_abort () at abort.c:92
#2  0x40054244 in *__GI_abort () at abort.c:92
#3  0x40054244 in *__GI_abort () at abort.c:92
#4  0x40054244 in *__GI_abort () at abort.c:92
#5  0x40054244 in *__GI_abort () at abort.c:92
#6  0x40054244 in *__GI_abort () at abort.c:92
... and so on ...

Now, the question: I'm totally unable to find the function causing the stack smashing from GDB even though the smash() function don't overwrite any structural data of the stack, only the stack protector itself. What should I do?

A: 

Have you tried resolving this complaint: "../nptl/sysdeps/unix/sysv/linux/raise.c: No such file or directory." to see if actually being able to resolve symbols would help?

Eric Towers
No I haven't but GDB isn't missing symbol information at the given location, only the source code file for the listing. Yet, I'll try your suggestion... Thanks
Dr. Sbaitso
Well, I tried this with no luck. GDB showed the source line in raise.c but the backtrace is still corrupt.
Dr. Sbaitso
A: 

It's not the case that GDB can always work out what happened to a smashed stack even with -fstack-protector-all (and even with -Wstack-protector to warn about functions with frames that weren't protected). Example.

In these cases the stack protector has done its job (killed a misbehaving app) but hasn't done the debugger any favors. (The classic example is a stack smash where a write has occurred with a large enough stride that it jumps the canary.) In these cases it may become necessary to binary search through the code via breakpoints to narrow down which region of the code is causing the smash, then single step through the smash to see how it happened.

Eric Towers
+3  A: 

The problem is that the version of GCC which compiled your target libc.so.6 is buggy and did not emit correct unwind descriptors for __GI_raise. With incorrect unwind descriptors, GDB gets into a loop while unwinding the stack.

You can examine the unwind descriptors with

readelf -wf /home/andersn/workspace/stacktest/linux/toolchain/lib/libc.so.6

I expect you'll get exact same result in GDB from any program calling abort, e.g.

#include <stdlib.h>
void foo() { abort(); }
int main() { foo(); return 0; }

Unfortunately, there isn't much you can do, other than trying to build newer version of GCC, and then rebuilding the whole "world" with it.

Employed Russian
Yep, that should be it, in a nutshell. However, it may suffice to rebuild libc.so with a new compiler.
Rebuilding just libc.so.6 may not be enough: after all, there is no guarantee that foo() will get correct unwind descriptor with the "old" GCC either.
Employed Russian