2010-08-09 97 views
5

我想知道是否有一種方法可以在Linux 進程的地址空間(從進程本身內部,通過 mprotect())寫保護每一頁。通過「每一頁」,我的意思是每個頁面的進程的地址空間可能會被一個普通的 程序在用戶模式下運行 - 所以程序文本,常量,全局變量和堆 - - 但我會很滿意常量,全局變量和堆。我不想寫保護堆棧 - 似乎是一個壞主意。我可以在Linux進程的地址空間中寫保護每個頁面嗎?

一個問題是,我不知道從哪裏開始寫保護 內存。查看/proc/pid/maps,其中顯示了用於給定pid的內存 的各個部分,但他們似乎始於具有程序文本的地址 0x08048000。 (在Linux中,據我所知, 一個進程的內存是用底部的 底部的程序文本進行佈局的,然後是常量,然後是全局變量,然後是堆,然後是 一個大小不同的空白空間堆的大小或者堆棧的大小,然後堆棧從內存頂部向下增長,在 虛擬地址0xffffffff。)有一種方法可以告訴堆的頂端是哪個堆(是通過調用sbrk(0),它只是返回一個指向 當前「中斷」的指針,即堆頂部),但不是真正的方法來告訴堆的開始位置。

如果我試圖保護從0x08048000到中斷的所有頁面,我最終會得到mprotect: Cannot allocate memory錯誤。我不知道爲什麼mprotect會是 無論如何分配內存 - 谷歌是不是很有幫助。有任何想法嗎?

順便說一句,我想這樣做的原因是因爲我希望創建一個在程序的運行過程中寫入的所有頁面的 列表, ,我能想到的這樣做的方法是對所有頁面進行寫保護,讓任何嘗試寫入導致寫入錯誤,然後執行寫入 錯誤處理程序,該頁面將頁面添加到列表中,然後刪除寫入 保護。我想我知道如何實現處理程序,如果只有我能 找出哪些頁面要保護以及如何去做。

謝謝!

+1

我其實已經有了代碼,完全符合你想要做的事情。你的想法會起作用,但是你無法保護你的「這些頁面被寫入」列表所在的頁面,或者你的SEGV處理程序將導致SEGV! – Borealid 2010-08-10 00:36:08

+0

@Borealid,謝謝,現在我正試圖解決這個問題(我已經有了segfault處理程序,並且/ proc/self/maps解析現在可以工作)。如何避免保護包含該列表的頁面?在堆棧上分配列表可行,但我沒有看到任何方式將它傳遞給處理程序。另外,我可以將它作爲全局分配,但我想使用比定長數組(比如STL容器)更出色的數據結構,並且我可能並不總是知道我寫入的列表位於何處在記憶中。 – 2010-08-11 00:13:45

+0

@borealid:你說你有這樣做的代碼 - 你介意分享你的代碼嗎?我是新來的,而且我找不到直接與您聯繫的方式(反向頻道)。我正在努力完成Linsey正在做的事情,所以任何代碼示例都會非常有幫助。 – 2010-11-21 17:37:41

回答

5

如果您嘗試在未映射的頁面上調用它,則您從mprotect()收到ENOMEM

最好的辦法是打開/proc/self/maps,並在fgets()的某個時間讀一行,以查找您的過程中的所有映射。對於不是堆棧(在最後一個字段中指示)的每個可寫入映射(在第二個字段中指示),請調用mprotect(),並輸入正確的基地址和長度(從第一個字段中的開始和結束地址開始計算)。

請注意,您需要在此時設置您的故障處理程序,因爲讀取maps文件本身的行爲可能會導致在您的地址空間內寫入數據。

+0

謝謝 - 我希望能有一些解決/ proc/self/maps的方法,但似乎沒有(來自http://stackoverflow.com/questions/269314的討論)/IS-有-A-更好的路超解析進程內自映射到數字輸出,內存保護中)。 – 2010-08-10 14:35:54

0

開始簡單。寫保護幾頁,並確保您的信號處理程序適用於這些頁面。然後擔心擴大保護範圍。例如,你可能並不需要寫保護的代碼段:操作系統可以實現寫有或執行上的內存,將防止代碼段從以往保護語義寫到:

+0

是的,對於這個問題,我們現在可以假設沒有自修改代碼。無論是寫保護代碼段還是不寫代碼都可以,無論哪個更容易。 – 2010-08-10 14:39:29

+0

其實我想說的是你的代碼段很可能已經被寫保護了。 – 2010-08-10 15:47:21

相關問題