strace
を実行するように指示されたbash
シェルで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
_
私の質問は次のとおりです。それは正常ですか(もしそうなら、どのような理由で)_/usr/bin/mkdir
_ stat()
がたくさんありますか?出力行には番号が付けられており、特に_2776
_がすでに実行された後、行_2771
_はどのような意味を持つのでしょうか。また、execve
が一度に情報を提供するはずだったので、bashは_2770
_から最後のstat
までのすべてのシステムコールを保存できたのではないかという印象を受けました。何が足りないのですか?
それ以来、私は説明を求め、代替シェルdash
シェルがどのように動作するかを確認しましたが、stat()
も表示されます:
_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
_は、行_2767
_、2768 _are because of searching the executable in the various directories in the current
_ PATH`と同様です。
これが割り引かれる場合、dash
は単一の統計のみを実行し、bash
は10を実行します。もう一度質問を提起します:これは正常ですか?
UPDATE: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()
とアクセスの組み合わせは、glibc
のint eaccess(const char *pathname, int mode);
ライブラリ関数。 eaccess
を使用するたびに、すべてのgeteuid
、getguid
、getuid
、getgid
、およびaccess
が使用されます。これは、bashが実行されるためです findcmd.c の_file_status
_関数が2回実行されます。
_#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つのシステムコールにリンクされている可能性があります。
findcmd.c:find_user_command_in_path()
のループを確認する必要があります。
stat()
は、パス内の要素ごとに2回( file_status()
から)呼び出されます。1回はfind_in_path_element()
行 640 で、1回はis_directory()
行 645 。
おっしゃるように、file_status()
が呼び出されるのもeaccess()
です。
これは最適化できますが、パスがハッシュされ、コマンドが初めて使用されたときにのみこの検索と統計が行われるため、大したことではないことに注意してください。