为什么我使用ld-2.31.so可以在没有执行权限的情况下执行文件?
Why I can execute files without execution permission if I use ld-2.31.so?
我对这个发现有点震惊。
如果我没有文件的执行权限,比如说,foo...我仍然可以执行它:
/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 ./foo
(ld-linux-x86-64.so.2
是 ld-2.31.so
的符号链接)。
因为我不认为我知道那个命令到底发生了什么,因为我真的不知道 ld-2.31.so
是什么,你能解释一下为什么可以执行文件吗?当我们只是做 ./foo
时,这是在我们看不到的背景中发生的事情吗?什么是 ld-2.31.so ?它的作用是什么?还有其他做类似工作的“技巧”和库(我不知道它们的用途,实际上我是新手)吗?
Is this what happens in background that we don't see, when we just do ./foo ?
有点。发生的事情是内核
- 检查
./foo
是否具有执行权限
mmap
根据里面的程序头(readelf -Wl foo
)生成文件
- 注意到文件有
PT_INTERP
段,读取其内容(通常 /lib64/ld-linux-x86-64.so.2
在 Linux x86_64
系统上)
mmap
根据自己的程序头解释解释器
- 将控制转移给用户 space 中的解释器。然后由解释器完成加载任何需要的共享库并初始化它们,最后将控制权转移到
foo
s _start
.
由于此启动顺序,对于动态链接的 ./foo
,数千条指令中的 10 秒在 _start
之前执行。
这也是让 ./foo
可执行文件成为可能的方式,但是对于 运行 的尝试,它会产生“没有这样的文件或目录”。您可以自己尝试一下:
gcc main.c -Wl,--dynamic-linker=/foo/bar/baz
ls -l a.out
./a.out
I can still execute it with: /path/to/ld.so ./foo
在这种情况下,您将跳过“正常”执行路径中的几个步骤。
从内核的角度来看,ld.so
是一个静态链接的二进制文件,它 是 可执行文件,因此内核很乐意 mmap
它的段和将控制权移交给它。
并且 ld.so
本身认识到它是通过命令行参数以“不寻常”的方式调用的,因此它继续执行 ./foo
s 段的额外映射(这已经由否则内核)。为了执行映射,ld.so
只需要一个文件;它不关心该文件的权限。
事实证明这种操作模式非常有用,例如测试 ld.so
本身的新版本。
它还允许你 运行 一个缺少解释器的二进制文件(上面的 a.out
):/lib64/ld-linux-x86-64.so.2 ./a.out
可以工作,而 ./a.out
不工作。
我对这个发现有点震惊。 如果我没有文件的执行权限,比如说,foo...我仍然可以执行它:
/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 ./foo
(ld-linux-x86-64.so.2
是 ld-2.31.so
的符号链接)。
因为我不认为我知道那个命令到底发生了什么,因为我真的不知道 ld-2.31.so
是什么,你能解释一下为什么可以执行文件吗?当我们只是做 ./foo
时,这是在我们看不到的背景中发生的事情吗?什么是 ld-2.31.so ?它的作用是什么?还有其他做类似工作的“技巧”和库(我不知道它们的用途,实际上我是新手)吗?
Is this what happens in background that we don't see, when we just do ./foo ?
有点。发生的事情是内核
- 检查
./foo
是否具有执行权限 mmap
根据里面的程序头(readelf -Wl foo
)生成文件- 注意到文件有
PT_INTERP
段,读取其内容(通常/lib64/ld-linux-x86-64.so.2
在 Linuxx86_64
系统上) mmap
根据自己的程序头解释解释器- 将控制转移给用户 space 中的解释器。然后由解释器完成加载任何需要的共享库并初始化它们,最后将控制权转移到
foo
s_start
.
由于此启动顺序,对于动态链接的 ./foo
,数千条指令中的 10 秒在 _start
之前执行。
这也是让 ./foo
可执行文件成为可能的方式,但是对于 运行 的尝试,它会产生“没有这样的文件或目录”。您可以自己尝试一下:
gcc main.c -Wl,--dynamic-linker=/foo/bar/baz
ls -l a.out
./a.out
I can still execute it with:
/path/to/ld.so ./foo
在这种情况下,您将跳过“正常”执行路径中的几个步骤。
从内核的角度来看,ld.so
是一个静态链接的二进制文件,它 是 可执行文件,因此内核很乐意 mmap
它的段和将控制权移交给它。
并且 ld.so
本身认识到它是通过命令行参数以“不寻常”的方式调用的,因此它继续执行 ./foo
s 段的额外映射(这已经由否则内核)。为了执行映射,ld.so
只需要一个文件;它不关心该文件的权限。
事实证明这种操作模式非常有用,例如测试 ld.so
本身的新版本。
它还允许你 运行 一个缺少解释器的二进制文件(上面的 a.out
):/lib64/ld-linux-x86-64.so.2 ./a.out
可以工作,而 ./a.out
不工作。