hum*_*ace 6 bash dash stat syscalls
strace在bash被指示运行的shell 上运行mkdir提供了此输出,该输出显示了执行实际mkdir二进制文件之前的大量统计信息:
BASH$> strace -f sh -c "bash -c \"mkdir /tmp\" 2>&1 | nl | grep -e "execve\|stat\|access"
[.....]
2766 [pid 17371] stat(".", {st_mode=S_IFDIR|0750, st_size=17262, ...}) = 0
2767 [pid 17371] stat("/usr/local/sbin/mkdir", 0x7ffd87aad0a0) = -1 ENOENT 2767 (No such file or directory)
2768 [pid 17371] stat("/usr/local/bin/mkdir", 0x7ffd87aad0a0) = -1 ENOENT (No such file or directory)
2769 [pid 17371] stat("/usr/bin/mkdir", {st_mode=S_IFREG|0755, st_size=51136, ...}) = 0
2770 [pid 17371] stat("/usr/bin/mkdir", {st_mode=S_IFREG|0755, st_size=51136, ...}) = 0
2771 [pid 17371] access("/usr/bin/mkdir", X_OK) = 0
2772 [pid 17371] stat("/usr/bin/mkdir", {st_mode=S_IFREG|0755, st_size=51136, ...}) = 0
2773 [pid 17371] access("/usr/bin/mkdir", R_OK) = 0
2774 [pid 17371] stat("/usr/bin/mkdir", {st_mode=S_IFREG|0755, st_size=51136, ...}) = 0
2775 [pid 17371] stat("/usr/bin/mkdir", {st_mode=S_IFREG|0755, st_size=51136, ...}) = 0
2776 [pid 17371] access("/usr/bin/mkdir", X_OK) = 0
2777 [pid 17371] stat("/usr/bin/mkdir", {st_mode=S_IFREG|0755, st_size=51136, ...}) = 0
2778 [pid 17371] access("/usr/bin/mkdir", R_OK) = 0
2779 [pid 17371] execve("/usr/bin/mkdir", ["mkdir", "/tmp"], 0x557ec7e15920 /* 5 vars */) = 0
Run Code Online (Sandbox Code Playgroud)
我的问题是:是否正常(如果是,出于什么原因)被/usr/bin/mkdir stat()编辑了很多?输出行已编号,特别是我想知道 line 2776make 一旦2771已经运行有什么意义。另外我下的印象庆典可能已保存的所有systemcalls从2770以后到最终execve作为stat应该提供一次信息?我错过了什么?
从那以后,我寻求解释并检查了外壳的替代外壳的dash行为方式,它还显示了一些stat()ing:
DASH$> strace -f sh -c "dash -c \"mkdir /tmp\" 2>&1 | nl | grep -e "execve\|stat\|access"
[....]
2792 [pid 17372] stat("/usr/local/sbin/mkdir", 0x7ffc66010b50) = -1 ENOENT (No such file or directory)
2793 [pid 17372] stat("/usr/local/bin/mkdir", 0x7ffc66010b50) = -1 ENOENT (No such file or directory)
2794 [pid 17372] stat("/usr/sbin/mkdir", {st_mode=S_IFREG|0755, st_size=51136, ...}) = 0
2795 [pid 17372] execve("/usr/sbin/mkdir", ["mkdir", "/run"], 0x55d8d3453bb8 /* 6 vars */) = 0
Run Code Online (Sandbox Code Playgroud)
我知道,行2792,2793类似的线2767,2768 are because of searching the executable in the various directories in the currentPATH`。
如果这被打折,那么dash只做一个单一的统计,bash做 10。再次提出问题:这正常吗?
更新:
有更多的geteuid(),getguid(),getuid()并getgid()在bash的统计混到
BASH$>strace -f sh -c "bash -c \"mkdir /tmp\"" 2>&1 | grep -e "execve\|stat\|access\|geteuid\|getegid\|getuid\|getgid"
[....]
[pid 24534] stat("/usr/local/bin/mkdir", 0x7fffda480f30) = -1 ENOENT (No such file or directory)
[pid 24534] stat("/usr/local/sbin/mkdir", 0x7fffda480f30) = -1 ENOENT (No such file or directory)
[pid 24534] stat("/usr/bin/mkdir", {st_mode=S_IFREG|0755, st_size=51136, ...}) = 0
[pid 24534] stat("/usr/bin/mkdir", {st_mode=S_IFREG|0755, st_size=51136, ...}) = 0
[pid 24534] geteuid() = 1000
[pid 24534] getegid() = 1000
[pid 24534] getuid() = 1000
[pid 24534] getgid() = 1000
[pid 24534] access("/usr/bin/mkdir", X_OK) = 0
[pid 24534] stat("/usr/bin/mkdir", {st_mode=S_IFREG|0755, st_size=51136, ...}) = 0
[pid 24534] geteuid() = 1000
[pid 24534] getegid() = 1000
[pid 24534] getuid() = 1000
[pid 24534] getgid() = 1000
[pid 24534] access("/usr/bin/mkdir", R_OK) = 0
[pid 24534] stat("/usr/bin/mkdir", {st_mode=S_IFREG|0755, st_size=51136, ...}) = 0
[pid 24534] stat("/usr/bin/mkdir", {st_mode=S_IFREG|0755, st_size=51136, ...}) = 0
[pid 24534] geteuid() = 1000
[pid 24534] getegid() = 1000
[pid 24534] getuid() = 1000
[pid 24534] getgid() = 1000
[pid 24534] access("/usr/bin/mkdir", X_OK) = 0
[pid 24534] stat("/usr/bin/mkdir", {st_mode=S_IFREG|0755, st_size=51136, ...}) = 0
[pid 24534] geteuid() = 1000
[pid 24534] getegid() = 1000
[pid 24534] getuid() = 1000
[pid 24534] getgid() = 1000
[pid 24534] access("/usr/bin/mkdir", R_OK) = 0
[pid 24534] execve("/usr/bin/mkdir", ["mkdir", "/tmp"], 0x55adcd4dc040 /* 55 vars */) = 0
Run Code Online (Sandbox Code Playgroud)
所以也许这可以为 bash 的“这里发生的事情”提供线索?是否进行一些检查以防止setuid漏洞利用?
**更新2:**的geteuid(),getguid(),getuid(),getgid()并获得组合似乎是使用的标志glibc的int eaccess(const char *pathname, int mode);库函数。每次使用都会eaccess导致使用 all geteuid, getguid, getuid, getgidand access,因为 bash 运行findcmd.c的file_status函数,而后者又像这样运行 eaccess 两次。
#if defined (HAVE_EACCESS)
/* Use eaccess(2) if we have it to take things like ACLs and other
file access mechanisms into account. eaccess uses the effective
user and group IDs, not the real ones. We could use sh_eaccess,
but we don't want any special treatment for /dev/fd. */
if (eaccess (name, X_OK) == 0)
r |= FS_EXECABLE;
if (eaccess (name, R_OK) == 0)
r |= FS_READABLE;
Run Code Online (Sandbox Code Playgroud)
每个 eaccess 可能链接到 4 个系统调用。
小智 3
你应该看看 中的循环findcmd.c:find_user_command_in_path()。
stat()对于路径中的每个元素(从 )调用file_status()两次:一次 viafind_in_path_element()在第640行,一次 viais_directory()在第645行。
正如您所提到的,它也在所谓的file_status()之中eaccess()。
虽然这可以优化,但请记住,这没什么大不了的,因为路径随后被散列,并且所有这些搜索和统计仅在第一次使用命令时发生。