Val*_*ami 13 linux filesystems bash fedora c
任何人都可以详细解释以下内容。让我们假设我正在安装一个带有noexec选项的目录,如下所示:
mount -o noexec /dev/mapper/fedora-data /data
Run Code Online (Sandbox Code Playgroud)
所以为了验证这一点,我跑了mount | grep data:
/dev/mapper/fedora-data on /data type ext4 (rw,noexec,relatime,seclabel,data=ordered)
Run Code Online (Sandbox Code Playgroud)
现在/data我正在创建一个简单的脚本hello_world,如下所示:
#!/bin/bash
echo "Hello World"
whoami
Run Code Online (Sandbox Code Playgroud)
因此,我使脚本可执行chmod u+x hello_world(但这对带有noexec选项的文件系统没有影响)并尝试运行它:
# ./hello_world
-bash: ./hello_world: Permission denied
Run Code Online (Sandbox Code Playgroud)
但是,准备bash文件会产生:
# bash hello_world
Hello World
root
Run Code Online (Sandbox Code Playgroud)
然后我创建了一个简单hello_world.c的内容如下:
#include <stdio.h>
int main()
{
printf("Hello World\n");
return 0;
}
Run Code Online (Sandbox Code Playgroud)
编译它使用 cc -o hello_world hello_world.c
现在运行:
# ./hello_world
-bash: ./hello_world: Permission denied
Run Code Online (Sandbox Code Playgroud)
所以我尝试使用它来运行它
/lib64/ld-linux-x86-64.so.2 hello_world
Run Code Online (Sandbox Code Playgroud)
错误:
./hello_world: error while loading shared libraries: ./hello_world: failed to map segment from shared object: Operation not permitted
Run Code Online (Sandbox Code Playgroud)
所以这当然是正确的,因为ldd返回以下内容:
ldd hello_world
ldd: warning: you do not have execution permission for `./hello_world'
not a dynamic executable
Run Code Online (Sandbox Code Playgroud)
在noexec安装选项不适用的另一个系统上,我看到:
ldd hello_world
linux-vdso.so.1 (0x00007ffc1c127000)
libc.so.6 => /lib64/libc.so.6 (0x00007facd9d5a000)
/lib64/ld-linux-x86-64.so.2 (0x00007facd9f3e000)
Run Code Online (Sandbox Code Playgroud)
现在我的问题是:为什么在带有noexec选项的文件系统上运行 bash 脚本而不是c编译的程序?引擎盖下发生了什么?
mat*_*tdm 27
这两种情况发生的事情是一样的:要直接执行文件,需要设置执行位,并且不能挂载文件系统 noexec。但是这些东西并不能阻止任何东西读取这些文件。
当 bash 脚本以 as 运行./hello_world并且文件不可执行时(没有 exec 权限位,或者文件系统上没有 exec ),甚至没有检查该#!行,因为系统甚至不加载文件。在相关意义上,脚本永远不会“执行”。
就 而言bash ./hello_world,简单的 noexec 文件系统选项并不像您希望的那样智能。bash运行的命令是/bin/bash,并且/bin不在带有noexec. 所以,它运行没有问题。系统不关心 bash(或 python 或 perl 或其他)是解释器。它只是运行您提供的命令 ( /bin/bash) 和恰好是一个文件的参数。在 bash 或其他 shell 的情况下,该文件包含要执行的命令列表,但现在我们“过去”了要检查文件执行位的任何内容。该检查不对以后发生的事情负责。
考虑这个案例:
$ cat hello_world | /bin/bash
Run Code Online (Sandbox Code Playgroud)
……或者对于那些不喜欢毫无意义地使用 Cat 的人:
$ /bin/bash < hello_world
Run Code Online (Sandbox Code Playgroud)
#!当您尝试将文件作为命令执行时,文件开头的“shbang”序列只是一些很好的魔法,可以有效地执行相同的操作。您可能会发现这篇 LWN.net 文章很有帮助:程序如何运行。
kas*_*erd 12
以前的答案解释了为什么noexec当/bin/bash从命令行显式调用解释器(在您的情况下)时,设置不会阻止脚本运行。但是,如果仅此而已,则此命令也可以正常工作:
/lib64/ld-linux-x86-64.so.2 hello_world
Run Code Online (Sandbox Code Playgroud)
正如你所指出的那样,这是行不通的。那是因为noexec还有另一个作用。内核将不允许来自该文件系统的内存映射文件PROT_EXEC启用。
内存映射文件用于多种场景。两个最常见的场景是可执行文件和库。当使用execve系统调用启动程序时,内核将在内部为链接器和可执行文件创建内存映射。所需的任何其他库都由链接器通过启用的mmap系统调用映射到内存PROT_EXEC。如果您尝试使用来自文件系统的库,noexec内核将拒绝进行mmap调用。
当您调用系统调用时/lib64/ld-linux-x86-64.so.2 hello_world,execve系统调用只会为链接器创建内存映射,链接器将打开hello_world可执行文件并尝试以与为库所做的几乎相同的方式创建内存映射。这是内核拒绝执行mmap调用并且您收到错误的点:
./hello_world: error while loading shared libraries: ./hello_world: failed to map segment from shared object: Operation not permitted
Run Code Online (Sandbox Code Playgroud)
该noexec设置仍然允许在没有执行权限的情况下进行内存映射(有时用于数据文件),并且它还允许正常读取文件,这就是为什么bash hello_world对您有用。