有人可以协助解释具有术语 'stack smash' 的回溯输出吗?

标签 c linux

请解释在运行程序后堆栈粉碎的以下结果,其中我提供的输入远远超过字符数组的容量。

    *** stack smashing detected ***: ./a.out terminated
             ======= Backtrace: =========
/lib/tls/i686/cmov/libc.so.6(__fortify_fail+0x48)[0xb7f856d8]
/lib/tls/i686/cmov/libc.so.6(__fortify_fail+0x0)[0xb7f85690]
./a.out[0x804845f]
    [0x666a6473]
======= Memory map: ========
08048000-08049000 r-xp 00000000 08:07 91312      /home/mawia/a.out
08049000-0804a000 r--p 00000000 08:07 91312      /home/mawia/a.out 
0804a000-0804b000 rw-p 00001000 08:07 91312      /home/mawia/a.out
084cd000-084ee000 rw-p 084cd000 00:00 0          [heap]
b7e6d000-b7e7a000 r-xp 00000000 08:07 221205     /lib/libgcc_s.so.1
b7e7a000-b7e7b000 r--p 0000c000 08:07 221205     /lib/libgcc_s.so.1
b7e7b000-b7e7c000 rw-p 0000d000 08:07 221205     /lib/libgcc_s.so.1
b7e8a000-b7e8b000 rw-p b7e8a000 00:00 0 
b7e8b000-b7fe3000 r-xp 00000000 08:07 238955     /lib/tls/i686/cmov/libc-2.8.90.so
b7fe3000-b7fe5000 r--p 00158000 08:07 238955     /lib/tls/i686/cmov/libc-2.8.90.so
b7fe5000-b7fe6000 rw-p 0015a000 08:07 238955     /lib/tls/i686/cmov/libc-2.8.90.so
b7fe6000-b7fe9000 rw-p b7fe6000 00:00 0 
b7ff6000-b7ff9000 rw-p b7ff6000 00:00 0 
b7ff9000-b8013000 r-xp 00000000 08:07 221196     /lib/ld-2.8.90.so
b8013000-b8014000 r-xp b8013000 00:00 0          [vdso]
b8014000-b8015000 r--p 0001a000 08:07 221196     /lib/ld-2.8.90.so
b8015000-b8016000 rw-p 0001b000 08:07 221196     /lib/ld-2.8.90.so
bfd00000-bfd15000 rw-p bffeb000 00:00 0          [stack]
Aborted

请解释以下内存映射的细节以及本报告中给出的各种细节的意义。

编辑:

代码只是简单地输入一个字符串。我故意输入的字符串的大小大于我定义的字符数组的长度,以产生堆栈粉碎。 代码:

 int main()

 {
  int a;
  char s[10];
  scanf("%s",s);
  return 0;
 }

谢谢。

最佳答案

编辑:只需重新阅读您的问题的标题。你想知道为什么它被称为 Stack Smash。当您调用在 C 中创建的数组的函数时,会为您的所有局部变量、函数的参数和函数的返回地址生成一个框架。这个框架是在堆栈上制作的,被称为堆栈框架;听起来很公平。这个栈帧应该只属于那个函数,并且应该与它周围的其他栈帧有边界;如果它可以改变其他堆栈框架,后果可能是可怕的。它会打破整个“功能有自己的范围”的想法。因此,因为你的数组是一个局部变量,它被放置在那个堆栈帧中,当你在其中放置太多信息时,你只是继续写入,直到到达堆栈帧的边界,然后你继续前进,C 将让你那样做。它设定了界限并让您随意打破它们。这种超出框架边界的行为被称为“粉碎”堆栈,因为您正好跑过其他重要数据。破坏堆栈就是在不应该写入的地方破坏堆栈数据。

首先我应该说它不会给你太多信息,除非你碰巧知道哪些 c 指令被放置在内存的哪个部分。

回溯会告诉您在失败之前正在运行的代码;即你的程序在你溢出的数组上调用了 libc 代码。

内存映射告诉您内存的哪些部分专用于什么,例如您的程序在哪里,它调用的库在哪里,堆在哪里以及堆栈在哪里。它还为您提供了那些内存位置 rwxp 的权限(读取、写入、可执行、PROC_STACK),尽管我不确定 PROC_STACK 位。

基本上,除非您知道您的程序在内存中的映射,否则这是无用的信息。您也可以使用更有用的调试器。这告诉你一些事情:

  1. 您的程序破坏了 libc,这可能意味着多种情况。
  2. 您用代码破坏了堆栈。

我假设您知道您的数组是在调用它的函数的堆栈帧中初始化的,因此,当您压入太多值时,您会离开帧并破坏堆栈。

希望对您有所帮助。如果您想了解更多,请询问。

关于有人可以协助解释具有术语 'stack smash' 的回溯输出吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/789900/

相关文章:

C预处理器字符串化怪异

c - 尝试使用链接列表运行程序并收到 "Segmentation Fault 11"

linux - 有没有办法让 PostgreSQL 在使用某种语言进行整理时不折叠标点符号和空格?

linux - SO_BINDTODEVICE 虚拟接口(interface)失败

linux - 每天监视文件夹的 Shell 脚本,如果该文件夹上未生成新文件,将发送邮件警报

c - 为什么我的 flex 代码中有无法识别的规则?

c++ - 将字符串转换为 int 数组的最简单方法

c - Jprobe 不监控所有 `do_execve` 调用

linux - zcat 文件是 gzip 格式还是非 gzip 格式

linux - sed 无法使用 bash 脚本注释文件中的一行