2016-11-16 68 views
1

我有一個非常簡單的ELF可執行文件:爲什麼linux內核將我的RW片段映射爲RWX?

$ readelf -l ./plt.out 

Elf file type is EXEC (Executable file) 
Entry point 0x400338 
There are 7 program headers, starting at offset 64 

Program Headers: 
    Type   Offset    VirtAddr   PhysAddr 
       FileSiz   MemSiz    Flags Align 
    PHDR   0x0000000000000040 0x00000000003ff040 0x00000000003ff040 
       0x0000000000000188 0x0000000000000188 R E 8 
    LOAD   0x0000000000000000 0x00000000003ff000 0x00000000003ff000 
       0x0000000000001000 0x0000000000001000 RW  1000 
    INTERP   0x00000000000001c8 0x00000000003ff1c8 0x00000000003ff1c8 
       0x0000000000000032 0x0000000000000032 R  1 
     [Requesting program interpreter: /data/keno/new_glibc/usr/lib/ld-linux-x86-64.so.2] 
    LOAD   0x0000000000001000 0x0000000000400000 0x0000000000400000 
       0x00000000000003b0 0x00000000000003b0 R E 1000 
    LOAD   0x0000000000001ea0 0x0000000000600ea0 0x0000000000600ea0 
       0x0000000000000180 0x0000000000000180 RW  1000 
    DYNAMIC  0x0000000000001ea0 0x0000000000600ea0 0x0000000000600ea0 
       0x0000000000000150 0x0000000000000150 RW  8 
    GNU_RELRO  0x0000000000001ea0 0x0000000000600ea0 0x0000000000600ea0 
       0x0000000000000160 0x0000000000000160 R  1 

現在,從我如何ELF作品的理解,我希望三個部分:

  • 一個RW從0x3ff000-0x400000
  • 一個RX從0x400000-0x401000
  • 來自0x600000-0x602000的一個RW(0xea0+0x180 > 0x1000

然而,當我真正看到我所得到的,而可執行文件是使用/proc/pid/maps運行,我看到以下內容:

003ff000-00400000 rwxp 00000000 00:28 1456774       plt.out 
00400000-00401000 r-xp 00001000 00:28 1456774       plt.out 
00600000-00601000 r-xp 00001000 00:28 1456774       plt.out 
00601000-00602000 rwxp 00002000 00:28 1456774       plt.out 

這根本不是我的預期。這裏發生了什麼?

回答

5

這裏的答案是雙重的,一部分由動態鏈接器貢獻,另一部分由內核貢獻。要看到這一點,讓我們在進入動態鏈接器後立即查看內存映射(例如,通過在_dl_start中設置斷點)。我們看到:

003ff000-00400000 rwxp 00000000 00:28 1456774       plt.out 
00400000-00401000 r-xp 00001000 00:28 1456774       plt.out 
00600000-00602000 rwxp 00001000 00:28 1456774       plt.out 

它至少接近我們想要的(它在正確的位置具有正確的片段)。現在,最後一個段被拆分的原因是因爲GNU_RELRO程序頭,它對動態鏈接器說:「嘿,在完成最初的重定位後,我不需要再寫這個了」,so the dynamic linker faithfully tries to set that region of memory to PROT_READ (注意它忽略了在程序頭文件中設置的實際許可標誌,雖然它們看起來通常設置爲PF_R)。

雖然這只是神祕的一半。我們仍然有那些討厭的PROT_EXEC位,我們沒有訂購。這些都歸結爲Linux內核的一個名爲READ_IMPLIES_EXEC特性的特性,導致所有具有PROT_READ權限的地圖也具有PROT_EXEC權限(請參閱man page for personality(2))。事實證明,出於兼容性原因,linux automatically sets this personality除非PT_GNU_STACK程序頭文件 告訴它不要。如果所有輸入對象都有(空).note.GNU-stack部分,鏈接器會自動創建此程序標題。有關該機制的更多信息,請參閱here

相關問題