是否可以通过分配系统上的所有空白空间来从另一个程序读取内存?


26

从理论上讲,如果我要构建一个程序来分配系统上所有未使用的内存,并继续请求越来越多的内存,因为其他应用程序释放了它们不再需要的内存,则可以从另一个应用程序读取最近释放的内存?还是受到现代操作系统的某种保护?

我对此没有实际应用,我只是很好奇。我意识到现实生活中分配“所有可用内存”存在一些问题。

编辑:为澄清起见,我专门询问“已释放”内存,而不访问其他应用程序当前分配的内存。

Answers:


23

不可以,因为好的内核会在将内存内容发布给进程之前先擦除内存内容,以防止您提出的确切攻击类型。

在Unixy系统上,通过扩展所谓的program break来为进程分配内存,这是进程可以使用的虚拟地址空间的限制。一个进程告诉内核它想扩展其可寻址空间,如果内存可用,内核将允许它,否则,调用将失败。(brk()系统调用的名称来自此概念。)

在实践中,大块的释放内存通常不会与程序中断相抵触,这是通过缩小程序中断使进程将内存返回内核的过程所需要的。当然,这完全取决于系统对malloc()和的实现free()。如果您有可用的资源,它们会告诉您是否返回了内存。

malloc()不初始化内存没有安全隐患,因为通过它获取的任何内容brk()都会被清除,而先前free()d的任何内容都将由同一进程写入。


19

是的,从理论上讲,可以读取另一个进程的已释放内存。过去,它是许多特权升级攻击的源头。因此,如果操作系统先前已将其分配给另一个进程,则如今的操作系统实际上会将内存归零。您并不总是看到内存清零的原因是,如果先前由同一进程分配了内存,则不将内存清零更为有效。如果可能,操作系统会尝试将内存页面退还给同一进程。


1
“是但不”是“否”。@Blrfl说对了。
Ross Patterson

4
@RossPatterson:从理论上讲,Karl实际上比我正确。实际情况是,主流操作系统在几年前就已经关闭了这个漏洞。
Blrfl 2013年

@Blrfl理解了。但是“几年前”是在1960年代后期,当时首次引入了分页系统和虚拟内存。当然在Multics,VM / 370和OS / VS时代。没有错误,大多数实践程序员都无法做到这一点。
罗斯·帕特森

The reason you don't always see zeroed out memory is because it is more efficient not to zero out the memory if it was previously allocated by the same process 我在这里看到一些不一致之处。您是说“相同的可执行文件”吗?如何通过磁盘路径检查是否不归零?
jakub.g

1
我想我缺少了一些东西。为什么当我使用未初始化的整数编译和运行某些C ++程序时,当我读取这些变量时它们不等于0?
jakub.g

2

这里涉及影响答案的几层。

如果您假设使用现代虚拟内存操作系统,则将无法在分配的页面中看到其他进程数据的剩余部分。

首次加载进程时,将加载页表,并可能将实际内存的帧分配给这些页。页表或其补充表至少将包含该进程可以分配的所有内存的映射。这也是设置上面提到的初始过程中断的地方。

尽管如果允许进程,则malloc()可能会导致进程中断更改,将更多页添加到进程页(补充页)表中以满足请求,但一个进程可能“获取另一个”进程数据的位置较低的实内存层。

在这两种情况下,使用需求分页或延迟分配的现代操作系统都尚未分配物理内存(帧)。操作系统只是“记录”该进程的哪个虚拟内存被视为有效。仅在需要时才分配实际内存。

当实现虚拟页面并将其映射到进程页面表时,将物理内存或帧分配给进程。这是存在数据泄露的地方。这是在页面错误期间发生的。出现这种情况的原因是,先前的进程可能一直在使用同一帧,并且其数据被放弃或换出,以便为当前的物理内存请求腾出空间。操作系统必须小心,以确保在继续过程之前正确交换了请求的过程数据或清除了帧(将其清零)。上面也将其称为“古老但已解决”的问题。

这是否使其他进程的内存“释放”了一点无关紧要。另一个进程“已释放”的内存仍驻留在分配给该进程的页面中,通常直到该进程结束时才被取消映射,因为它们将在内存不足或被逐出时被换出。malloc()和free()在(用户)级别管理分配给进程的虚拟内存。

在您的问题中,从理论上讲,您的进程将继续请求越来越多的内存,从而将所有其他进程推出内存。实际上,有一些全局和局部的帧分配策略也可能会影响答案。在允许进程溢出操作系统和所有其他进程之前,该进程很可能会强制将其自己的页面移出内存。虽然这超出了您最初的问题。

在像MS-DOS这样的系统中,所有这些都是没有意义的。MS-DOS(以及其他更简单的系统)不使用虚拟内存(单独使用),并且您可以轻松地戳戳并处理另一个“处理”数据。

一本很好的操作系统教科书,Silberscatz,Gavin和Gange撰写的《操作系统概念》,或Andrew Tanenbaum撰写的《操作系统设计》,可能比Linux源代码更容易理解。同样,诸如来自伯克利的Nachos或来自斯坦福的Pintos之类的东西都是为学习而构建的小型操作系统,它们内部具有相同的想法。


0

我几个月前在Ubuntu 16.04上尝试了这个。就像0xACE所说的那样,现代操作系统一旦调用malloc()就会分配全零的虚拟页面。但是,如果您不向分配的缓冲区写入任何内容,则不会将其映射到物理内存中(即写时复制原理),因此,您始终会从“未初始化的”块中读取零。也许有些嵌入式操作系统使用“ CONFIG_MMAP_ALLOW_UNITIALIZED”选项进行编译以获得更好的性能,在这种情况下,您可以获得您所期望的。


-1

不,由于分页的魔力,这将不允许另一个程序读取另一个人的内存。这样,通过将部分内存卸载到硬盘驱动器,可以使总内存使用量超过物理内存。

同样,一个进程可以分配的最大内存由操作系统任意限制(对于32位体系结构,最多可以分配4个演出),然后下一次alloc调用将返回内存不足错误。


难道没有特定于平台的API可以规避吗?我真的不知道,但是我不会感到惊讶(例如,Linux允许通过阻止OS将页面移出物理内存mlock)。

如果有4 GB的RAM,而分页限制为8 GB,那么如果应用程序请求12 GB(在x64上)该怎么办?
阿森尼

那么,当剩余的可用内存太少时,系统调用应该返回错误,否则,计算机将在没有剩余可用空间时立即停止运行……
棘手怪胎

4
他不是在问读别人的记忆,而是在念他们的已释放记忆。ram的该部分当前是空闲的,并且....我不认为...分页方案在释放后会将内存归零。因此,程序将分配一块内存,并分析已经存在的未初始化数据。
菲利普(Philip)

@philip是正确的,我专门询问释放的内存。
ConditionRacer
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.