堆栈溢出检测与堆溢出检测

7
在像Linux这样的需求分页系统中,页面大小可能为4k(根据我所看到的)。为了确保保护,它会检查堆栈或堆大小是否超过每个给定页面的数量。当我创建两个变量时,这种保护机制被启用。
char *s = (char *) malloc(100);   
char sa[100];

在for循环中,我可以写大约4000次s[i] = 'c';,然后它就会出现内存错误,而对于sa[i] = 'c';,在数组大小之外的任何地方都会出现segmentation faultstack smashing错误。我可以理解第一种情况下会出现页错误,并且它会发现没有更多的页面被分配到堆中,因此会发生内存违规。但是第二种情况会发生什么呢?gcc是否在运行时为所有预分配变量进行检查?
编辑:我在下面发布整个代码。
int main(int argc,char* argv[]){
char *s = (char *) malloc(20);
char sa[400] = {0};
int i ,count;
printf(" enter the number of chars to write: ");
scanf("%d",&count);
for (i=0;i<count;i++){
printf("%d\n",i);
sa[i] = 'a';
//s[i] = 'a';
}
free(s);

}

从语言角度来看,这两种情况完全未定义。为实现特定问题添加了一个“gcc”标签。 - Bo Persson
请注意,并不能保证您只能使用堆栈分配的变量来编写数组的长度。在我的 x86_64 机器上,我可以写到 2880(其中 &sa[i] == 0x7ffffffff000,达到了新的页面)。 - user786653
我假设我们会忽略你为什么要写入已经超出分配范围的数组这个问题,对吧? - Christian Semrau
@christian-semrau 是的... - dasman
你说的堆栈增长是什么意思?如果是for循环,那么每次循环时堆栈都会被重置到相同的位置。或者这个for循环包含了递归调用吗? - QuentinUK
显示剩余2条评论
1个回答

2
在许多32位操作系统上,堆栈向下增长。您只使用正索引进入数组,因此取决于您的函数调用嵌套深度。当您从数组中索引时,将首先覆盖金丝雀。因此,堆栈溢出错误首先发生。接下来,您将开始覆盖函数参数和返回地址。如果没有金丝雀,那么函数返回会跳转到永远不存在的地方,通常会产生段错误。不总是这样,它可能会意外地落在有效代码上,这是堆栈缓冲区溢出攻击背后的逻辑。
随着继续进行,您最终会写入未分配的页面之上的堆栈顶部。然后就会产生段错误。在一个具有少数嵌套调用的小型测试程序中,这很快发生,大约需要几千字节左右。
还可以尝试使用负偏移量。这可以继续进行一段时间,否则不会造成任何问题,因为您正在写入未分配的堆栈空间。当您写入超过分配的堆栈大小时,通常为1兆字节,就会产生段错误。在Windows上,您将触发堆栈保护页,生成一个异常,该站点以此命名。

操作系统不是将堆栈、堆和代码视为不同的段吗?我最初想的是,堆栈获得一页,堆获得一页,因此随着它们的增长,会分配更多的页面。那么堆栈溢出如何覆盖代码部分呢? - dasman
它并没有。不确定你为什么得出那个结论。 - Hans Passant
我在操作系统的文本中读到,C编译器生成程序段作为代码、堆栈、全局等,但是Linux将代码放入[用户代码]段,所有其他数据(堆栈、堆等)放入[用户数据]段,然后使用分页。所以我知道Linux不会对堆栈和堆进行分段。但是如果[用户数据]段的初始分配小于所需(例如递归),那么它如何扩展堆栈? - dasman
Linux不断变化,现在不确定它的功能。Windows使用保留内存页,并通过页面错误转换为实际页。 Linux一段时间内不支持此操作,但现在也许已经支持了。这些都不是重点,或许你忽略了“堆栈向下增长”的开头句子。你正在写入已经分配的页面。 - Hans Passant
好的,堆栈向下增长,堆向上增长在逻辑地址空间中。因此,我可以在堆栈上写入,直到我引用的逻辑地址之一没有分配页面->段错误。在我上面的代码中,我已经初始化了char sa [400],当我循环约600次时会发生堆栈破坏...但是范围> 800的任何内容都会导致段错误。为什么堆栈破坏不总是最先发生?段错误在页面错误时被检测到,但是堆栈破坏只在循环结束时被检测到吗? - dasman
1
因为导致段错误的写入操作发生在检测到栈 Canary 被破坏之前的函数返回之前。关键的洞察力在于检查栈 Canary 的确切时间。直到函数返回才进行检查。 - Hans Passant

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接