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後跟零填充沒有填充零的優勢。這實際上是一個特定散列的約定,但就是這樣。它不允許你確定長度,除非1是非法字符。在任何情況下,長度必須單獨存儲。假設我的頁面裏有什麼是我的可能的(如Q中所述),但不一定是真的。這是真正的問題所在。也就是說,我可以同時確認它在至少3個Windows版本下可靠地工作(無論如何都由POSIX保證)。 – Damon
這對確定長度沒有幫助,但不需要「確定」它。您需要防止攻擊,因此填充可能足夠或可能不足,具體取決於散列(例如,對於CubeHash)。但我的觀點是,你需要更多的空間,而不僅僅是在街區盡頭的洞。 – maaartinus
我重複說,除非操作系統使用段寄存器,它在穿越頁面邊界之前沒有任何干擾。 AFAIK,沒有現代操作系統使用段寄存器,但這是你可以輕鬆檢查的東西。 – maaartinus