多年来,让调用堆栈允许代码执行一直是许多安全问题的根源。堆栈缓冲区溢出可用于利用编写错误的软件,其中可以执行存储在堆栈缓冲区中的代码。
我只是想知道是否真的有一个原因,它不仅仅是不可执行的?为什么调用堆栈上的任何东西都需要可执行?
也许有一些历史原因
答案 0 :(得分:7)
创建不可执行的堆栈需要硬件的帮助。早期的英特尔处理器没有NX位,直到386或奔腾才真正有用。 (早期的处理器确实没有执行保护。但它并不是无处不在。)
在不同时期,人们已经使用可执行堆栈甚至可写代码段来编写自修改程序。我想我们都同意自修改代码是一个坏主意,但我记得当我在80年代开始时对它有很多兴趣。如果你抛弃代码和数据之间任意分离的麻烦限制,你真的可以编写一些非常紧凑的程序。
说到这一点,执行数据和在堆栈中存储大量数据的概念是Lisp的重要组成部分。有关如何影响JIT编译器的一个讨论,请参阅Allocating a data page in linux with NX bit turned off。如果你想JIT编译非常小的东西,那么在堆栈上分配和运行它会很方便。
那就是说,正如你所说的,这是一个很大的问题,这就是为什么通常会离开它的原因。这将哈佛大学的一些建筑带回到我们大多数人已经长大的冯·诺伊曼建筑中。
答案 1 :(得分:3)
自20世纪40年代以来,大多数计算机都故意不区分可执行和非可执行内存。这种单一,统一的代码和数据模型是Von Neumann architecture的关键方面之一。在不同的时间,在各种内存管理设计中引入了一些有限的非执行功能,实际上现在大多数CPU和操作系统都支持将单个内存页标记为不可执行。