gpt4 book ai didi

linux - dlopen() 如何创建只读 VMA?

转载 作者:塔克拉玛干 更新时间:2023-11-03 00:31:40 25 4
gpt4 key购买 nike

我研究了 dlopen() 在 Linux 下如何在内存中加载动态库。但我找不到 glibc 库如何或在何处创建内存中的只读区域。

Glibc 的 dlopen() 使用程序头来查找类型为 LOAD 的段并将它们映射到内存中。对于动态库,这只是前两个:

Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flags Align
LOAD 0x0000000000000000 0x0000000000000000 0x0000000000000000 0x000000000000075c 0x000000000000075c R E 0x200000
LOAD 0x0000000000000e00 0x0000000000200e00 0x0000000000200e00 0x0000000000000228 0x0000000000000230 RW 0x200000
...

保护位(前一列)用于第一次读/执行和第二次读/写。相应的部分是:

 Section to Segment mapping:
Segment Sections...
00 .note.gnu.build-id .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt .init .plt .plt.got .text .fini .rodata .eh_frame_hdr .eh_frame
01 .init_array .fini_array .jcr .dynamic .got .got.plt .data .bss

从init进程中随机选择一个动态库的内存布局如下:

7f4b67833000-7f4b67837000 r-xp 000000 08:01 393388 /lib/x86_64-linux-gnu/libcap.so.2.25
7f4b67837000-7f4b67a37000 ---p 004000 08:01 393388 /lib/x86_64-linux-gnu/libcap.so.2.25
7f4b67a37000-7f4b67a38000 r--p 004000 08:01 393388 /lib/x86_64-linux-gnu/libcap.so.2.25
7f4b67a38000-7f4b67a39000 rw-p 005000 08:01 393388 /lib/x86_64-linux-gnu/libcap.so.2.25

在这种情况下,有一个额外的内存区域,只有读取设置的保护位。这样做的原因是什么,这是在哪里完成的?为什么 .rodata 部分包含在数据可执行的第一个段中?

加载部分在elf/dl-load.c中完成:

有趣的函数是 _dl_map_segments,它在第 1181 行从 _dl_map_object_from_fd 函数调用。此函数在文件 elf/dl-map-segments.h 中定义.

但是这个函数只映射段及其保护位。我错过了什么吗?

最佳答案

中间的只读区域是使用mprotect 创建的,以响应PT_GNU_RELRO 程序头。这是由 eu-readelf 输出建议的:

Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
LOAD 0x000000 0x0000000000000000 0x0000000000000000 0x001698 0x001698 R 0x1000
LOAD 0x002000 0x0000000000002000 0x0000000000002000 0x001b01 0x001b01 R E 0x1000
LOAD 0x004000 0x0000000000004000 0x0000000000004000 0x000bdc 0x000bdc R 0x1000
LOAD 0x005950 0x0000000000006950 0x0000000000006950 0x000800 0x000808 RW 0x1000
DYNAMIC 0x005cf0 0x0000000000006cf0 0x0000000000006cf0 0x0001f0 0x0001f0 RW 0x8
NOTE 0x000238 0x0000000000000238 0x0000000000000238 0x000024 0x000024 R 0x4
GNU_EH_FRAME 0x0045b4 0x00000000000045b4 0x00000000000045b4 0x00010c 0x00010c R 0x4
GNU_STACK 0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RW 0x10
GNU_RELRO 0x005950 0x0000000000006950 0x0000000000006950 0x0006b0 0x0006b0 R 0x1

Section to Segment mapping:
Segment Sections...
00 [RO: .note.gnu.build-id .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt]
01 [RO: .init .plt .plt.got .text .fini]
02 [RO: .rodata .eh_frame_hdr .eh_frame]
03 [RELRO: .init_array .fini_array .data.rel.ro .dynamic .got] .data .bss
04 [RELRO: .dynamic]
05 [RO: .note.gnu.build-id]
06 [RO: .eh_frame_hdr]
07
08 [RELRO: .init_array .fini_array .data.rel.ro .dynamic .got]

(我假设您的示例共享对象来自 Debian 10 或一些类似的发行版。)

PT_GNU_RELROelf/dl-load.c 中与其他程序头一起被解析。重定位完成后,只读设置本身应用于 elf/dl-reloc.c 函数 _dl_protect_relroRELRO 代表重定位(然后)只读

只读部分没有单独的 PT_LOAD 段,因为最初出于性能原因希望限制加载段的数量,但这不再适用由于竞争要求。

关于linux - dlopen() 如何创建只读 VMA?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57383299/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com