为什么 linux 上无法读取的 ELF 可以是 运行?
Why does an unreadable ELF on linux can be run?
我理解如果脚本不可读(即使它是可执行的)则不能 运行 因为解释器需要阅读它。
但是为什么linux上的一个不可读的二进制文件可以是运行(我用gcc把我的代码编译成./my_exe
并设置为0100权限)?执行二进制文件总是需要一些阅读,对吗?然后我读了这个 Can a file that is executable be read?,但我仍然有一些疑问。
execve(2) 告诉我内核会调用 /lib/ld-linux.so.2
到 运行 程序(我用 readelf 查看,它确实有 INTERP 段,也就是 /lib64/ld-linux-x86-64.so.2
),所以我认为 /lib64/ld-linux-x86-64.so.2
是 user-space ELF 加载程序(它执行动态链接并将 ELF 映射到内存中)。由于我无法读取 ELF,我想我不应该 运行 它因为 运行 需要读取它的 GOT 才能进行动态链接。事实证明我真的不能 运行 像 /lib64/ld-linux-x86-64.so.2 my_exe
那样。我只是收到它无法加载共享对象的消息。但是当我 运行 它直接从 bash 像 ./my_exe
时,它是 运行 成功的。
我的问题是:既然执行ELF涉及ld-linux-x86-64.so.2
,为什么我编译的0100权限的程序可以直接运行? ld-linux-x86-64.so.2
应该是读不出来,所以应该是读不到GOT,做动态链接。那为什么我直接运行就成功了呢?
ld.so 是你的二进制地址 space 的一部分,它是由内核加载的,目的是加载其他(动态)库。当它已经被内核加载到内存中时,为什么它应该从磁盘读取你的二进制文件?所以 ld.so 没有读取任何内容,因此没有通过安全检查。
Did you mean, when kernel do execve it will do mmap for both PT_INTERP
and the ELF itself with proper permission (like make the GOT
readable-ly mmaped)
有的,可以自己查here
static int load_elf_binary(struct linux_binprm *bprm)
...
if (elf_interpreter) {
unsigned long interp_map_addr = 0;
elf_entry = load_elf_interp(&loc->interp_elf_ex,
interpreter,
&interp_map_addr,
load_bias, interp_elf_phdata);
我理解如果脚本不可读(即使它是可执行的)则不能 运行 因为解释器需要阅读它。
但是为什么linux上的一个不可读的二进制文件可以是运行(我用gcc把我的代码编译成./my_exe
并设置为0100权限)?执行二进制文件总是需要一些阅读,对吗?然后我读了这个 Can a file that is executable be read?,但我仍然有一些疑问。
execve(2) 告诉我内核会调用 /lib/ld-linux.so.2
到 运行 程序(我用 readelf 查看,它确实有 INTERP 段,也就是 /lib64/ld-linux-x86-64.so.2
),所以我认为 /lib64/ld-linux-x86-64.so.2
是 user-space ELF 加载程序(它执行动态链接并将 ELF 映射到内存中)。由于我无法读取 ELF,我想我不应该 运行 它因为 运行 需要读取它的 GOT 才能进行动态链接。事实证明我真的不能 运行 像 /lib64/ld-linux-x86-64.so.2 my_exe
那样。我只是收到它无法加载共享对象的消息。但是当我 运行 它直接从 bash 像 ./my_exe
时,它是 运行 成功的。
我的问题是:既然执行ELF涉及ld-linux-x86-64.so.2
,为什么我编译的0100权限的程序可以直接运行? ld-linux-x86-64.so.2
应该是读不出来,所以应该是读不到GOT,做动态链接。那为什么我直接运行就成功了呢?
ld.so 是你的二进制地址 space 的一部分,它是由内核加载的,目的是加载其他(动态)库。当它已经被内核加载到内存中时,为什么它应该从磁盘读取你的二进制文件?所以 ld.so 没有读取任何内容,因此没有通过安全检查。
Did you mean, when kernel do execve it will do mmap for both PT_INTERP and the ELF itself with proper permission (like make the GOT readable-ly mmaped)
有的,可以自己查here
static int load_elf_binary(struct linux_binprm *bprm)
...
if (elf_interpreter) {
unsigned long interp_map_addr = 0;
elf_entry = load_elf_interp(&loc->interp_elf_ex,
interpreter,
&interp_map_addr,
load_bias, interp_elf_phdata);