2011-07-14 44 views
1

POSIX说“系统总是在一个对象的末尾零填充任何部分页。此外,系统从未写出一个对象,该超出其端部的最后一页的任何修改的部分。 “,而且Linux和FreeBSD文档在其手册页中都有相似的措词。
这表明,虽然它不是严格合法的阅读最后尾随字节(因为它们是映射的范围之外),它仍然是明确定义和设计的方式,因此可以发生没有崩溃。即使写入该区域也是一种明确定义。最后映射页面

,另一方面

Windows文档不说的尾随字节的任何一个低于块大小范围,确实警告说,创建比文件会增加文件大小和大的映射不一定会零数据。
我倾向于认为这是错误的信息或历史(可能追溯到Win95?)。 SetFileValidData需要非标准的用户权限,因为这可能会使先前删除的文件中的数据可见。如果Windows内核开发人员允许任何人通过映射任何随机文件轻易绕过这一点,他们将不得不相当愚蠢。
我在Windows XP的观察是,任何新的网页显然是从零池中提取,而对于空页写回,或者将文件默默做出稀疏,或回写是一个非常,非常聪明的方式(没有进行任何明显的延迟在任何时候,甚至在技嘉范围内)。

那么,什么是对的问题?

我需要计算文件的散列值(可能是成千上万的)来检测文件的一个子集,已被修改。人们可以假定SHA-256算法,尽管实际的算法并不重要。
因此,这当然不是什么大的挑战,但是像每个软件一样,它应该立即运行并且不使用内存,等等。通常的现实的期望,你得到它:-)

计算这样一个哈希的正常方法是检查消息是否有根据散列函数的块大小(例如说64字节)和零 - 如果不是这种情况,填写最后一个不完整的块。另外,散列可能有对齐要求。
这通常意味着您必须创建完整的消息副本,或者编写一些特殊代码,其中除了一个块外,还会加上最后一个块的零填充副本。或类似的东西。散列算法通常也以自己的名义默默地做这种事情。在任何情况下,它都会涉及大量数据并且比人们希望的更复杂。

现在有直接散列掀起了内存映射文件,并依赖于一个事实,即文件映射必然取决于内存页的诱惑。因此,起始地址和物理映射长度或多或少地保证是4kB的倍数(在一些系统上是64kB)。当然,这意味着它们自动也是64,128的整数倍,或者散列可能具有的任何其他块大小。
出于安全原因,实际上没有任何操作系统能够承担给你一个包含陈旧数据的页面。

这意味着您可以在整个文件中进行天真散列而不必担心对齐,填充或任何操作,并避免复制数据。它可能读取映射范围末尾的几个字节,但它仍然必须位于同一页面内。

我当然知道这是在技术上非法。读取映射范围之外的最后一个字节与说malloc(5)总是返回一个8字节的块相似,所以使用额外的3个字节是安全的。

虽然除了那个显而易见的事情,我认为这将“合理地工作”是合理的,还是存在一些严重问题,我在任何主要平台上都看不到?

我并不是真的对理论或历史操作系统都太感兴趣,但我想保持的便携性。也就是说,我希望确保它可以在您可能遇到的任何桌面计算机或“典型托管服务器”(主要是Windows,Linux,BSD,OSX)上可靠地运行。
如果存在一个从1985年开始的操作系统,它将最后一个页面标记为不可读,并且在其错误处理程序中强制执行严格的字节范围,那么我就可以。你不能(也不应该)让每个人都开心。

回答

1

正常的方法来计算这样的散列是检查该消息是否按照所述散列函数的块大小的尺寸(比如例如64个字节)和零填补最后不完全块,如果这是不案件。

不是。这样你就无法找出最后一个块的长度(是零还是来自填充)。填充的工作方式有点不同:在一个模式中,您总是追加一个1,然后0 s直到块的结尾。

如果数据在块边界处结束,则意味着需要另一个块。这个额外的块可能会落在一个额外的页面中。所以我认为它不会像你所描述的那样工作。

它可能会在映射范围的末尾读取几个字节,但它仍然必须位于同一页面内。

我认为这应该适用于Intel/AMD,因为没有人可以对付它。 i386 + CPU具有段和页面。段可以在任何字节边界上结束,但AFAIK当前没有OS使用它们。所以只要你留在你的页面,这都是你的。

所以,我认为它可以工作是这样的:

  • 的情况下,最后的块尚未全尺寸,做填充到位
  • 否则,运行在一个恒定的准备最后一轮块如1000000000000000
+0

添加一个1后跟零填充没有填充零的优势。这实际上是一个特定散列的约定,但就是这样。它不允许你确定长度,除非1是非法字符。在任何情况下,长度必须单独存储。假设我的页面里有什么是我的可能的(如Q中所述),但不一定是真的。这是真正的问题所在。也就是说,我可以同时确认它在至少3个Windows版本下可靠地工作(无论如何都由POSIX保证)。 – Damon

+0

这对确定长度没有帮助,但不需要“确定”它。您需要防止攻击,因此填充可能足够或可能不足,具体取决于散列(例如,对于CubeHash)。但我的观点是,你需要更多的空间,而不仅仅是在街区尽头的洞。 – maaartinus

+0

我重复说,除非操作系统使用段寄存器,它在穿越页面边界之前没有任何干扰。 AFAIK,没有现代操作系统使用段寄存器,但这是你可以轻松检查的东西。 – maaartinus