【问题标题】:Why does the linux kernel map my RW segment as RWX?为什么linux内核将我的RW段映射为RWX?
【发布时间】:2017-03-30 03:20:03
【问题描述】:

我有一个非常简单的 ELF 可执行文件:

$ 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 工作原理的理解,我预计分为三个部分:

  • 一个来自0x3ff000-0x400000的RW
  • 来自0x400000-0x401000 的一个 RX
  • 来自0x600000-0x602000 (0xea0+0x180 > 0x1000) 的一个 RW

但是,当我使用/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

这完全不是我所期望的。这是怎么回事?

【问题讨论】:

    标签: linux linux-kernel glibc dynamic-linking


    【解决方案1】:

    这里的答案是双重的,一部分由动态链接器贡献,另一部分由内核贡献。为了看到这一点,让我们在进入动态链接器后立即查看内存映射(例如,通过在 _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 程序头,它对动态链接器说“嘿,在你完成初始重定位后,我不需要再写这个了”,@ 987654321@(注意它忽略了程序头中设置的实际权限标志,尽管它们似乎通常设置为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

    【讨论】:

    猜你喜欢
    • 2014-02-15
    • 2019-01-13
    • 2020-08-17
    • 1970-01-01
    • 1970-01-01
    • 2010-12-20
    • 2020-05-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多