Red Hat Enterprise Linux 6 のシェル スクリプトの execvp exec 形式エラー

Red Hat Enterprise Linux 6 のシェル スクリプトの execvp exec 形式エラー

カーネルと glibc の同一バージョン (glibc–2.12–1.90.el6_3.6) を実行している 2 つの RHEL 6 システムがあります。POSIX 標準と Linux のマニュアル ページによると、カーネルが実行可能ファイルが ELF などの実行可能形式ではなく、shebang( #!) 行も含まれていないと判断した場合、関数execlexeclpexecleexecvexecvpexecvpe( は除く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__execveexecve

Linux でこの問題に遭遇した人は他にいますか? 私が試した他のすべてのシステムでは動作は正常です。

答え1

よし、問題の原因が分かった。x.c実行ファイルをコンパイルした後、実行してみると、実行ファイルに動的にリンクされたlddライブラリがあるのが分かった。このライブラリは、liboit.soObserveIT Unix 監査ツールは、システム コールを含む、ログインしたユーザーによるすべてのアクティビティをインターセプトします。ただし、 による再実行は/bin/shglibc 内で行われるため、システム コールをインターセプトするだけでは、観察された動作にはならないと思います。おそらく ObserveIT は、この状況では明らかに非準拠ですが、POSIX 関数もエミュレートします。

関連情報