我正在尝试让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必须是二维的)
答案 0 :(得分:3)
默认情况下,GCC只会添加代码来检测堆栈粉碎,当您执行特别危险的操作时,如alloca
(或gets
,如您在评论中提到的那样),或者声明一个大型自动数组。 / p>
如果要为所有功能启用保护,请使用-fstack-protector-all
选项。您还可以使用-Wstack-protector
请求有关不受保护的功能的警告。
答案 1 :(得分:1)
似乎gcc中决定何时启用堆栈保护的逻辑有点棘手。来自文档的第一个注释:
-fstack保护器
发出额外的代码来检查缓冲区溢出,例如堆栈粉碎攻击。这是通过向具有易受攻击对象的函数添加保护变量来完成的。这包括调用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
。