【问题标题】:Stack smashing not fires. Why?堆栈粉碎不火灾。为什么?
【发布时间】:2013-10-18 09:54:01
【问题描述】:

我正在尝试让 glibc 检测堆栈粉碎,我使用以下代码:

 #include <stdio.h>
 #include <string.h>

 static const int n = 5;

 int main(int argc, char *argv[])
 {
  if (argc != 2)
  {
     printf("usage: %s string\n", argv[0]);
     return -1;
  }
  printf("%s, len = %d\n", argv[1], strlen(argv[1]));
  unsigned char a[n][n];
  unsigned char * b = a[n - 1];
  memcpy(b, argv[1], (strlen(argv[1]) + 1) * sizeof(unsigned char));
  return 0;
 }

如果 argv[1] 长度大于 5,我希望检测到堆栈粉碎错误,但是,我没有,并且 valgrind 没有检测到错误。我应该改变什么来得到这个错误? (数组a必须是二维的)

【问题讨论】:

  • 这是 undefined 行为。
  • @MM.:确实。但是 OP 正在询问如何获得工具来检测此类问题(我认为)。
  • @OliCharlesworth 由于数组大小在编译期间是已知的,编译器可能决定只复制第一个 n 字节,根本不破坏堆栈。
  • 人们,停止使用这种“未定义的行为”标准。这个问题不是关于ISO C++,而是关于glibc。如果您想挑剔,请询问CPU。这很重要。
  • 未定义的行为意味着您所编码的内容并不“对编译器意味着任何有效的东西”。所以它可以用完全没有代码的代码替换有问题的部分,或者退出,或者编译器设计者决定用这样的东西做任何其他事情。换句话说,你不能依赖你的代码来做你写的事情。

标签: c++ c glibc stack-smash


【解决方案1】:

默认情况下,GCC 仅在您执行特别危险的操作(例如 alloca(或 gets,正如您在评论中提到的)或声明大型自动数组时添加代码以检测堆栈粉碎。

如果要为所有功能启用保护,请使用-fstack-protector-all 选项。您还可以使用-Wstack-protector 请求有关未受保护功能的警告。

【讨论】:

  • 迈克,你提到的“大”数字有准确的值吗?
  • @Anton:根据documentation,8字节。但这似乎与您所看到的不符,因此文档可能与现实不完全相符。
【解决方案2】:

gcc 中决定何时启用堆栈保护的逻辑似乎有点棘手。文档中的第一个注释:

-fstack-protector

发出额外的代码来检查缓冲区溢出,例如堆栈粉碎攻击。这是通过将保护变量添加到具有易受攻击对象的函数来完成的。这包括调用 alloca 的函数,以及缓冲区大于 8 字节的函数。进入函数时初始化守卫,然后在函数退出时检查。如果保护检查失败,则会打印一条错误消息并退出程序

因此,我们应该期望本地缓冲区小于 8 字节的函数不受保护。例如,这个:

int unprotected() {
    char a[5];
    strcpy(a, "this is much too long");
    return a[0];
}

gcc -fstack-protector -Wstack-protector 编译,给出类似警告

警告:堆栈保护器未保护功能:所有本地数组的长度都小于 8 字节 [-Wstack-protector]

因此,您可能认为您的char[5][5] 将受到保护,因为它的长度超过 8 个字节。但是,当我将它编译到汇编器时,我没有收到警告 堆栈保护(您可以在 this Dr. Dobbs article 中找到要查找的汇编器)。似乎 gcc 将其视为 5 个 5 字节的缓冲区,而不是 25 字节的单个缓冲区。

您可以通过向 gcc 显示大于 8 字节的单个缓冲区来说服 gcc 启用堆栈保护:

void protected(char *arg) {
    union {
        char dummy[5 * 5];
        char a[5][5];
    } u;
    memcpy(u.a[4], arg, (strlen(arg) + 1));
}

或者直接使用-fstack-protector-all

【讨论】:

  • 大于 8 字节的单个缓冲区没有得到这个错误,它似乎仍然不受保护,但 -fstack-protector-all 有所帮助。谢谢。
  • 而且,永远不要用“受保护”这个词来命名函数=)
  • 好点!我现在将离开它,并注意我在 C 中考虑的警告
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-06-26
  • 1970-01-01
  • 2011-11-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多