
カーネルと glibc の同一バージョン (glibc–2.12–1.90.el6_3.6) を実行している 2 つの RHEL 6 システムがあります。POSIX 標準と Linux のマニュアル ページによると、カーネルが実行可能ファイルが ELF などの実行可能形式ではなく、shebang( #!
) 行も含まれていないと判断した場合、関数execl
、execlp
、execle
、execv
、execvp
、execvpe
( は除くexecve
) は、Linux では である POSIX シェルを使用してそのファイルを実行しようとします/bin/sh
。
しかし、一方のシステムでは、最初の行が:
関数を使用しているシェル スクリプトの実行execvp
が失敗しますが、もう一方のマシンでは、スクリプトは/bin/sh
期待どおり を使用して実行されます。具体的には、次のテスト プログラムを使用しています。/tmp/test_script
は実行可能になります。
xc:
#include <stdio.h> #include <unistd.h> #include <stdlib.h> 外部char **environ; intメイン(){ char *argv[] = { "/tmp/test_script", NULL }; char *プログラム名 = argv[0]; (execvp(プログラム名, 引数) == -1)の場合{ perror("execvp"); -1 を返します。 } }
/tmp/テストスクリプト:
: echo "テストスクリプトが呼び出されました" 終了 0
インストールされたバージョンの glibc のソース RPM を検索したところ、目的の動作が確実に実装されています (execvp は execvpe の単純なラッパーです)。
posix/execvpe.c:
(strchr(ファイル, '/') != NULL)の場合 { /* スラッシュが含まれている場合は検索しません。 */ __execve(ファイル、引数、環境変数); (errno == ENOEXEC)の場合 { /* 引数を数えます。 */ 引数 = 0; while (argv[argc++]) ; size_t len = (argc + 1) * sizeof(char *); char **script_argv; void *ptr = NULL; __libc_use_alloca(len) の場合 script_argv = alloca(len); それ以外 script_argv = ptr = malloc(len); (script_argv != NULL) の場合 { scripts_argv(ファイル、argv、argc、script_argv); __execve(script_argv[0], script_argv, envp); 解放(ptr); } } } それ以外 ︙
ここで、 は引数リストの先頭にscripts_argv
追加する単純な関数であり、 glibc を介してユーザー空間に公開されると同一です。/bin/sh
__execve
execve
Linux でこの問題に遭遇した人は他にいますか? 私が試した他のすべてのシステムでは動作は正常です。
答え1
よし、問題の原因が分かった。x.c
実行ファイルをコンパイルした後、実行してみると、実行ファイルに動的にリンクされたldd
ライブラリがあるのが分かった。このライブラリは、liboit.so
ObserveIT Unix 監査ツールは、システム コールを含む、ログインしたユーザーによるすべてのアクティビティをインターセプトします。ただし、 による再実行は/bin/sh
glibc 内で行われるため、システム コールをインターセプトするだけでは、観察された動作にはならないと思います。おそらく ObserveIT は、この状況では明らかに非準拠ですが、POSIX 関数もエミュレートします。