注意:这个问题与堆栈溢出有关(想想无限递归),而不是缓冲区溢出。
如果我编写的程序是正确的,但它接受来自Internet的输入,该输入决定了它调用的递归函数中的递归级别,是否足以让某人破坏该机器?
我知道有人可能通过导致堆栈溢出来崩溃进程,但是他们是否可以注入代码?或者c运行时是否检测到堆栈溢出情况并干净地中止?
好奇......
答案 0 :(得分:4)
首先,您需要了解现代操作系统中的基本保护单元是进程和内存页面。进程是内存保护域;它们是操作系统执行安全策略的级别,因此它们与正在运行的程序强烈对应。 (他们不这样做,或者是因为程序在多个进程中运行,或者因为程序是在某种框架中共享的;后一种情况有可能是“安全性有趣”,但那是“其他故事”。)虚拟内存页面是硬件应用安全规则的级别;进程内存中的每个页面都有一些属性,用于确定进程可以对页面执行的操作:是否可以读取页面,是否可以写入页面,以及是否可以在页面上执行程序代码(尽管第三个属性更多)很少使用,也许它应该是)。编译的程序代码被映射到内存中,既可读也可执行但不可写,而堆栈应该是可读写的,但不可执行。 大多数内存页面根本不可读,不可写或不可执行; 操作系统只允许进程使用明确要求的页数,这就是内存分配库(malloc()
等。)为你管理。
如果每个堆栈帧都小于内存页 [1] ,那么当程序通过堆栈前进时,它会写入每个页面,操作系统(即,特权部分,运行时)至少原则上可以可靠地检测堆栈溢出,并在发生时终止程序。基本上,执行此检测的所有操作都是程序无法在堆栈末尾写入的页面;如果程序试图写入它,内存管理硬件会捕获它,操作系统有机会进行干预。
如果可以欺骗操作系统不设置这样的页面,或者如果堆栈帧变得如此之大并且稀疏地写入保护页面被跳过,则会出现潜在的问题。 (保留更多防护页面将有助于防止第二种情况成本很低;强制可变大小的堆栈分配 - 例如alloca()
- 总是在将控制权返回给程序之前写入它们分配的空间,因此检测到粉碎堆栈,可以防止第一个在速度方面有一些成本,尽管写入可能合理稀疏以保持成本相当小。)
这会带来什么后果?那么,操作系统必须通过内存管理做正确的事情。 (@ Michael的链接说明了当它出错时会发生什么。)但是让攻击者确定内存分配大小是不危险的,你不会立即强制写入整个分配; alloca
和C99可变大小的数组是一种特殊的威胁。而且,我会更加怀疑C ++代码,因为它往往会进行更多基于堆栈的内存分配;它可能没问题,但事情出错的可能性更大。
就个人而言,我更喜欢保持堆栈大小和堆栈帧大小,并在堆上执行所有可变大小的分配。在某种程度上,这是处理某些类型的嵌入式系统和使用大量线程的代码的遗留问题,但它确实使得防止堆栈溢出攻击变得更加简单;操作系统可以可靠地捕获它们,然后所有攻击者都是拒绝服务(令人讨厌,但很少致命)。我不知道这是否适合所有程序员。
[1] 典型页面大小:32位系统上为4kB,64位系统上为16kB。检查系统文档中的环境。
答案 1 :(得分:3)
当堆栈溢出时,大多数系统(如Windows)都会退出。我认为你不太可能在这里看到安全问题。至少,不是特权提升安全问题。你可能会得到一些拒绝服务的问题。
答案 2 :(得分:2)
没有普遍正确的答案......在某些系统上,堆栈可能会向下或向上增长以覆盖程序正在使用的其他内存(或其他程序或操作系统),但是在任何设计良好,模糊安全的情况下操作系统(Linux,任何常见的UNIX变种,甚至是Windows)都没有权限升级潜力。在某些系统上,禁用堆栈大小检查,地址空间可能接近或超过可用虚拟内存大小,允许内存耗尽对整个机器产生负面影响甚至降低,而不仅仅是过程,但默认情况下在良好的操作系统上有一个限制(例如Linux的limit / ulimit命令)。
值得一提的是,使用计数器通常也很容易对递归深度施加任意但非常大的限制:如果是单线程,则可以使用静态局部变量,或者最终参数(如果您的语言,则可以方便地默认为0)允许它,否则外部调用者第一次提供0。
答案 3 :(得分:1)
是的。有一些算法可以避免递归。例如,在算术表达式reverse polish notation的情况下,您可以避免递归。背后的主要思想是改变原始表达。可能会有一些可以帮助你的algorythm。
堆栈溢出的另一个问题是,如果错误处理不合适,它可能会导致任何问题。例如在Java StackOverflowError中解释它是一个错误,如果有人捕获Throwable,它就会被捕获,这是一个常见的错误。因此,在堆栈溢出的情况下,错误处理是一个关键问题。
答案 4 :(得分:0)
是的,确实如此。可用性是安全性的一个重要方面,大多被忽视。
不要陷入那个坑。
作为现代操作系统中安全意识知之甚少的一个例子,请看一下相对新发现的vulnerability,其中没有人完全修补过。有许多其他的特权升级漏洞示例,操作系统开发人员已将其视为拒绝服务攻击。