當加載啟用了 ASLR 的 PIE 可執行檔案時,Linux 會限制程式段到規范部分的映射(最多 0000_7fff_ffff_ffff)還是會使用完整的低部分(起始位 0)?
uj5u.com熱心網友回復:
顯然,Linux 不會為您的行程提供不可用的地址,這會使其在嘗試從_start. (或者如果接近截止,當它嘗試加載或存盤 .data 或 .bss 時)
這實際上會發生在試圖首先將 RIP 設定為非規范值的指令上,可能是 aniret或sysret1。
在具有 48 位虛擬地址的系統上,當表示為符號擴展的 64 位值時,零到0000_7fff_ffff_ffff 是虛擬地址空間的完整下半部分。
在支持 PML5(并由內核使用)的系統上,虛擬地址是 57 位寬,所以
零到00ff_ffff_ffff_ffff是低半規范范圍。
請參閱https://www.kernel.org/doc/Documentation/x86/x86_64/mm.txt - 第一行是用戶空間范圍。(它談論“56 位”虛擬地址。這是不正確或誤導性的,PML5 是 57 位,一個額外的全級別頁表,每級 9 位。所以低半部分是 56 位,第 57 位為 0,而高半部分為 56 位,第 57 位為 1。)
========================================================================================================================
Start addr | Offset | End addr | Size | VM area description
========================================================================================================================
| | | |
0000000000000000 | 0 | 00007fffffffffff | 128 TB | user-space virtual memory, different per mm
__________________|____________|__________________|_________|___________________________________________________________
| | | |
0000800000000000 | 128 TB | ffff7fffffffffff | ~16M TB | ... huge, almost 64 bits wide hole of non-canonical
| | | | virtual memory addresses up to the -128 TB
| | | | starting offset of kernel mappings.
__________________|____________|__________________|_________|___________________________________________________________
|
| Kernel-space virtual memory, shared between all processes:
...
或者對于 PML5:
0000000000000000 | 0 | 00ffffffffffffff | 64 PB | user-space virtual memory, different per mm
__________________|____________|__________________|_________|___________________________________________________________
| | | |
0000800000000000 | 64 PB | ffff7fffffffffff | ~16K PB | ... huge, still almost 64 bits wide hole of non-canonical
| | | | virtual memory addresses up to the -64 PB
| | | | starting offset of kernel mappings.
腳注 1:
正如 prl 指出的那樣,這種設計允許實作實際上只有 48 個實際位來存盤管道中任何位置的 RIP 值,除了跳轉和檢測有符號溢位,以防執行在最后進入非規范區域。(也許在每個必須存盤 uop 的地方都保存晶體管,它需要知道自己的地址。)不像你可以跳轉/憤怒到任意 RIP,然后 #GP(0) 例外將不得不推送正確的64 位非規范地址,這意味著 CPU 必須暫時記住它。
這對于除錯查看您從哪里跳轉也更有用,因此以這種方式設計規則是有意義的,因為沒有用例故意跳轉到非規范地址。(與跳轉到未映射頁面不同,#PF 例外處理程式可以修復這種情況,例如通過請求分頁,因此您希望故障地址是新的 RIP。)
有趣的事實:sysret在 Intel CPU 上與非規范 RIP 一起使用將 #GP(0) in ring 0 (CPL=0),因此 RSP 不會切換并且仍然 = 用戶堆疊。如果存在任何其他執行緒,這將使它們弄亂內核用作堆疊的記憶體。這是英特爾對 x86-64 的實作 IA-32e 中的一個設計缺陷。這就是為什么 Linux 使用iret從 syscall 入口點回傳用戶空間的原因,如果 ptrace 在此程序中已用于此行程。內核知道一個新的行程會有一個安全的 RIP,所以它實際上可以sysret用來更快地跳轉到用戶空間。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/368050.html
下一篇:如何進行移動安全測驗
