【问题标题】:Unable to find stack smashing function using GDB无法使用 GDB 找到堆栈粉碎功能
【发布时间】:2011-04-30 19:23:08
【问题描述】:

我有以下 C 应用程序:

#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;
}

我使用以下版本的 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) 

这样调用:

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

在目标上运行时,它会输出:

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

我在 gdb 中加载生成的核心转储,产生以下回溯:

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>
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/>...
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 ...

现在,问题来了: 我完全无法从 GDB 中找到导致堆栈粉碎的函数,即使smash() 函数不会覆盖堆栈的任何结构数据,只会覆盖堆栈保护器本身。我该怎么办?

【问题讨论】:

  • 我认为您的“等等”可能遗漏了一些重要信息。 __GI_abort 真的是栈底吗?
  • 我尝试继续 GDB 输出并在我放弃之前达到了 #11087.... 所有相同的帧。
  • 你明确地破坏了堆栈——不要指望核心文件有整齐的链接调用帧:)
  • 我认为堆栈应该是完全有效的,因为我只超出了合法范围的 1 个字节,这就是堆栈保护器的位置
  • @Nikolai N Fetissov:在 gcc (x86_64 4.4.5) 上按照上述配方在 Linux AMD64 (2.6.35) 上进行测试(循环上升到 31 和 ulimit -c 无限制)给出了一个带有 gdb (7.2) 正确解析的堆栈帧的核心转储。

标签: c gcc gdb


【解决方案1】:

问题是编译您的目标 libc.so.6 的 GCC 版本有问题,并且没有为 __GI_raise 发出正确的展开描述符。如果展开描述符不正确,GDB 在展开堆栈时会进入循环。

您可以使用

检查展开描述符
readelf -wf /home/andersn/workspace/stacktest/linux/toolchain/lib/libc.so.6

我希望你会从任何调用 abort 的程序在 GDB 中得到完全相同的结果,例如

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

不幸的是,除了尝试构建新版本的 GCC,然后用它重建整个“世界”之外,您无能为力。

【讨论】:

  • 是的,简而言之,应该就是这样。但是,使用新的编译器重建 libc.so 可能就足够了。
  • 仅重建 libc.so.6 可能还不够:毕竟,也不能保证 foo() 使用“旧”GCC 也能获得正确的展开描述符。
【解决方案2】:

即使使用 -fstack-protector-all (甚至使用 -Wstack-protector 来警告带有未受保护的帧的函数),GDB 也并非总能计算出损坏的堆栈发生了什么。 Example.

在这些情况下,堆栈保护器已经完成了它的工作(杀死了一个行为不端的应用程序),但没有给调试器带来任何好处。 (典型的例子是堆栈粉碎,其中写入发生的步幅足够大,以至于它会跳过金丝雀。)在这些情况下,可能需要通过断点对代码进行二进制搜索以缩小代码的哪个区域导致粉碎,然后单步通过粉碎,看看它是如何发生的。

【讨论】:

    【解决方案3】:

    您是否尝试过解决此投诉:“../nptl/sysdeps/unix/sysv/linux/raise.c: No such file or directory.”,看看实际能够解析符号是否会有所帮助?

    【讨论】:

    • 不,我没有,但 GDB 没有丢失给定位置的符号信息,只有清单的源代码文件。不过,我会试试你的建议...谢谢
    • 好吧,我试过了,但没有运气。 GDB 在 raise.c 中显示了源代码行,但回溯仍然损坏。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-01-13
    • 2012-07-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-18
    相关资源
    最近更新 更多