为啥堆栈不向上增长(为了安全)?

Posted

技术标签:

【中文标题】为啥堆栈不向上增长(为了安全)?【英文标题】:Why don't stacks grow upwards (for security)?为什么堆栈不向上增长(为了安全)? 【发布时间】:2011-02-14 05:29:28 【问题描述】:

这与问题'Why do stacks typically grow downwards?' 有关,但更多是从安全角度来看。我一般指的是x86。

当缓冲区通常在内存中向上写入时,堆栈会向下增长,这让我感到奇怪。例如,一个典型的 C++ 字符串的结尾比开头的内存地址更高。

这意味着如果存在缓冲区溢出,您将进一步覆盖调用堆栈,我理解这是一个安全风险,因为它打开了更改返回地址和局部变量内容的可能性。

如果堆栈在内存中向上增长,缓冲区溢出不会简单地运行到死内存中吗?这会提高安全性吗?如果是这样,为什么没有完成?那么 x64 呢,这些堆栈会向上增长吗?如果不是,为什么不呢?

【问题讨论】:

不确定它是否对防止堆栈缓冲区溢出问题有很大帮助。好吧,可能更多是在小端架构上。 您假设内存是连续映射的。没有什么可以阻止您在堆栈底部的内存映射中出现一个漏洞,以使缓冲区溢出运行到死内存中,但是您将堆栈限制在放置其基数的任何位置。此外,没有什么会迫使您将向上增长的堆栈放在内存空间末端附近。 【参考方案1】:

从技术上讲,这取决于 OS/CPU,但通常这是因为堆栈和堆从相反的方向和地址空间的两端增长。

这种安排为您在堆和堆栈之间拆分/分配内存提供了最大的灵活性,而不会导致它们发生冲突。如果它们都以相同的方向增长,那么您将需要有一个堆栈的起始地址,该地址将硬限制堆的最大大小(以及堆栈大小的硬限制)

预计到达时间:

找到了interesting piece on wikipedia,关于为什么让堆栈向上增长并不一定能防止堆栈溢出——它只是让它们的工作方式有所不同。

【讨论】:

有趣...那么为什么不交换堆栈和堆增长方向呢?我猜堆栈溢出比堆溢出更严重,对吧? @AshleysBrain - 也许新的 CPU 架构会这样做,但在现有 CPU 上更改它会破坏为该 CPU 编译的任何程序。可能只是一个糟糕的设计选择,早在人们对这些事情考虑太多之前就出现了——现在我们被它困住了。 我每天都访问 ***,但 heapoverflow 并没有那么多。所以我猜堆栈溢出更严重-:) 这就是我提到x64的原因,我认为他们可能在设计时抓住了机会改变了这一点,因为那时这个问题应该已经众所周知了。也许它会以某种方式破坏 x86 兼容性? @AshleysBrain - 这肯定会破坏兼容性,因为编写旧程序来操纵堆栈,就好像堆栈向下增长一样。可能只需要重新编译它们(使用新的编译器),但我认为它们不会是二进制兼容的。您可能还有一些程序以怪异的方式依赖此行为,这些程序也会完全中断。【参考方案2】:

好吧,我不知道堆栈增长方向是否会对安全性产生太大影响,但如果你看一下机器架构,在负地址方向增长堆栈确实简化了调用约定、堆栈帧指针、局部变量分配等等等等。

【讨论】:

【参考方案3】:

8088(x86 系列的开始)的体系结构使用向下扩展的堆栈,并且为了兼容性,从那时起就一直采用这种方式。那时,(80 年代初)家用计算机上的缓冲区溢出漏洞还远远没有引起人们的注意。

我无法告诉你为什么他们选择让它长大,而让它长大似乎更直观。但是,正如已经提到的,内存通常在堆栈和堆之间进行分割。也许 CPU 设计者认为堆增长很重要,因此堆栈增长。

【讨论】:

它比这更老 - 8080 的堆栈也向下增长,大概是 8008 的。我认为这与英特尔处理器一样古老。 @David:对,包括 4004 (download.intel.com/museum/archives/pdf/4004_datasheet.pdf)。我实际上使用我在课堂上演示的 8008 构建了一个小面包板系统。我将它编程为在一对扬声器上播放一个小二重唱。通过将电容器连接到内存定时器芯片,它会运行非常慢,以传达计算机之所以神奇只是因为它们速度快的概念。【参考方案4】:

可能是因为大多数 CPU 的架构是在男人还是男人的时代设计的,您可以相信您的程序员不想窃取人们的信用卡号码……现在改变大多为时已晚(尽管正如您所说,它可能适用于像安腾这样的新架构which actually has two stacks!)

【讨论】:

为什么这个答案被否决了?它揭示了事实。

以上是关于为啥堆栈不向上增长(为了安全)?的主要内容,如果未能解决你的问题,请参考以下文章

为啥局部变量在 Java 中是线程安全的

您将如何确定系统中的堆栈是向上还是向下增长? [复制]

我的堆栈是向上增长而不是向下增长吗? [复制]

为啥堆栈通常会向下增长?

为啥堆栈会增长到较低的地址? [复制]

为啥在函数中用作局部变量时数组不会沿堆栈方向增长?