AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / unix / 问题 / 475877
Accepted
humanityANDpeace
humanityANDpeace
Asked: 2018-10-17 10:09:07 +0800 CST2018-10-17 10:09:07 +0800 CST 2018-10-17 10:09:07 +0800 CST

在命令之前 bash stat() 和 access() 很多是正常的吗?

  • 772

在指示运行的 shell 上运行提供strace此输出,该输出在执行实际二进制文件之前显示大量统计信息:bashmkdirmkdir

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

我的问题是:是否正常(如果是,是什么原因)被/usr/bin/mkdir stat()大量使用?输出行已编号,特别是我想知道 line 2776make once2771已经运行有什么意义。此外,我的印象是 bash 可以保存从2770开始到最终execve的所有系统调用,因为它stat应该立即提供信息?我错过了什么?

从那以后,我一直在寻求解释并检查了 shell 的替代 shell 的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

我知道行2792,2793类似于行27672768 are because of searching the executable in the various directories in the currentPATH`。

如果打折,那么dash只做一个统计,bash做 10 个。再次提出问题:这正常吗?

更新:在 bash 统计中 有更多geteuid(), getguid(),getuid()和getgid()混杂

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

所以也许这可以为 bash 的“这里发生的事情”提供线索?是否正在做一些检查以防止setuid漏洞利用?

**更新 2:** geteuid()、getguid()、getuid()和getgid()access 组合似乎是 using库函数glibc的标志。int eaccess(const char *pathname, int mode);每次使用 都会eaccess导致使用 all geteuid、getguid、和getuid,因为 bash 运行findcmd.c的函数,而该函数又像这样运行 eaccess 两次。getgidaccessfile_status

#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;

其中每个 eaccess 可能链接到 4 个系统调用。

bash stat
  • 2 2 个回答
  • 295 Views

2 个回答

  • Voted
  1. Best Answer
    mosvy
    2018-10-17T12:31:31+08:002018-10-17T12:31:31+08:00

    你应该看看 中的循环findcmd.c:find_user_command_in_path()。

    stat()file_status()为路径中的每个元素调用 (from ) 两次:一次 viafind_in_path_element()在第640行,一次 viais_directory()在第645行。

    正如你提到的,它也在file_status()那个eaccess()被调用的地方。

    虽然这可以优化,但请记住这没什么大不了的,因为路径随后被散列,并且所有这些搜索和统计仅在第一次使用命令时发生。

    • 3
  2. humanityANDpeace
    2018-10-17T11:55:42+08:002018-10-17T11:55:42+08:00

    查看bash 的源代码,答案是:

    是的,通话是正常的,它们是由于多种因素造成的,包括

    1. bash运行一个file_status包含对的调用的函数,stat在大多数 GNU/Linux 中设置两个单独的调用eaccessfromglibc
    2. glibc的eaccess本身再次 stat运行,然后是一大堆快乐的geteuid, getegid, getuid,getgid最后access(因为它可能没有从它的 inital 记录任何有用的信息stat,也许 glibc 根本不想节省系统调用(上下文切换无关紧要!)。
    3. bash想要确保它找到的可以遍历目录的PATH文件对于尝试这样做的用户来说确实是可执行和可读的。(一测)
    4. bash运行一个hash表以减少连续调用的搜索路径(第二个测试与file_status)

    然后,这一切都会生成许多类似的多余系统调用。PATH 中的每个 cantate 的 6/11 系统调用和另一个 6/11 系统调用,一旦该命令先前被发现在哈希表中并因此被检查是否仍然有效。

    在我为我的 linux box 编译的情况下,file_statusbash 中的函数看起来像这样(即评估的 ifdefs)findcmd.c

    int
    file_status (name)
         const char *name;
    {
      struct stat finfo;
      int r;
    
      /* Determine whether this file exists or not. */
      if (stat (name, &finfo) < 0)
        return (0);
    
      /* If the file is a directory, then it is not "executable" in the
         sense of the shell. */
      if (S_ISDIR (finfo.st_mode))
        return (FS_EXISTS|FS_DIRECTORY);
    
      r = FS_EXISTS;
    
      /* 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 (exec_name_should_ignore (name) == 0 && eaccess (name, X_OK) == 0)
        r |= FS_EXECABLE;
      if (eaccess (name, R_OK) == 0)
        r |= FS_READABLE;
    
      return r;
    }
    

    stat()最初将运行一次,然后依次运行eaccess()两次(glibc函数运行:

    1. stat
    2. geteuid
    3. getguid
    4. getuid
    5. getgid
    6. access )

    因此负责原始 bash 输出的这一部分:

    [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
    
    • 0

相关问题

  • 通过命令的标准输出以编程方式导出环境变量[重复]

  • 从文本文件传递变量的奇怪问题

  • 虽然行读取保持转义空间?

  • `tee` 和 `bash` 进程替换顺序

  • 运行一个非常慢的脚本直到它成功

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    如何将 GPG 私钥和公钥导出到文件

    • 4 个回答
  • Marko Smith

    ssh 无法协商:“找不到匹配的密码”,正在拒绝 cbc

    • 4 个回答
  • Marko Smith

    我们如何运行存储在变量中的命令?

    • 5 个回答
  • Marko Smith

    如何配置 systemd-resolved 和 systemd-networkd 以使用本地 DNS 服务器来解析本地域和远程 DNS 服务器来解析远程域?

    • 3 个回答
  • Marko Smith

    如何卸载内核模块“nvidia-drm”?

    • 13 个回答
  • Marko Smith

    dist-upgrade 后 Kali Linux 中的 apt-get update 错误 [重复]

    • 2 个回答
  • Marko Smith

    如何从 systemctl 服务日志中查看最新的 x 行

    • 5 个回答
  • Marko Smith

    Nano - 跳转到文件末尾

    • 8 个回答
  • Marko Smith

    grub 错误:你需要先加载内核

    • 4 个回答
  • Marko Smith

    如何下载软件包而不是使用 apt-get 命令安装它?

    • 7 个回答
  • Martin Hope
    rocky 如何将 GPG 私钥和公钥导出到文件 2018-11-16 05:36:15 +0800 CST
  • Martin Hope
    Wong Jia Hau ssh-add 返回:“连接代理时出错:没有这样的文件或目录” 2018-08-24 23:28:13 +0800 CST
  • Martin Hope
    Evan Carroll systemctl 状态显示:“状态:降级” 2018-06-03 18:48:17 +0800 CST
  • Martin Hope
    Tim 我们如何运行存储在变量中的命令? 2018-05-21 04:46:29 +0800 CST
  • Martin Hope
    Ankur S 为什么 /dev/null 是一个文件?为什么它的功能不作为一个简单的程序来实现? 2018-04-17 07:28:04 +0800 CST
  • Martin Hope
    user3191334 如何从 systemctl 服务日志中查看最新的 x 行 2018-02-07 00:14:16 +0800 CST
  • Martin Hope
    Marko Pacak Nano - 跳转到文件末尾 2018-02-01 01:53:03 +0800 CST
  • Martin Hope
    Kidburla 为什么真假这么大? 2018-01-26 12:14:47 +0800 CST
  • Martin Hope
    Christos Baziotis 在一个巨大的(70GB)、一行、文本文件中替换字符串 2017-12-30 06:58:33 +0800 CST
  • Martin Hope
    Bagas Sanjaya 为什么 Linux 使用 LF 作为换行符? 2017-12-20 05:48:21 +0800 CST

热门标签

linux bash debian shell-script text-processing ubuntu centos shell awk ssh

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve