Red Hat Enterprise Linux 6 上的 shell 脚本的 execvp exec 格式错误

Red Hat Enterprise Linux 6 上的 shell 脚本的 execvp exec 格式错误

我们有两个 RHEL 6 系统,它们运行相同版本的内核和 glibc(glibc–2.12–1.90.el6_3.6)。根据 POSIX 标准和 Linux 手册页,如果内核确定可执行文件不是可执行格式(例如 ELF),并且没有 shebang ( #!) 行,则函数execlexeclpexecleexecvexecvpexecvpe(但不是execve)将尝试使用 POSIX shell 执行该文件,在 Linux 上是/bin/sh

但是,在其中一个系统上,执行第一行使用:函数的 shell 脚本execvp会失败,而在另一台机器上,该脚本会/bin/sh按预期使用执行。具体来说,我们使用这些测试程序;/tmp/test_script使其可执行:

xc:

#包括 <stdio.h>
#包括 <unistd.h>
#包括 <stdlib.h>

外部字符**环境;

int 主要 () {
        char *argv[] = { “/tmp/test_script”, NULL };
        char *程序名 = argv[0];
        如果 (execvp(程序名, argv) == -1) {
                perror(“execvp”);
                返回-1;
        }
}

/tmp/测试脚本:



echo“测试脚本已调用”
出口 0

我们已经在源 RPM 中搜索了已安装的 glibc 版本,它确实实现了所需的行为(execvp 是 execvpe 的简单包装器):

posix/execvpe.c:

如果 (strchr (文件,'/') != NULL)
    {
        /* 当包含斜杠时不要搜索。 */
        __execve(文件,argv,envp);

        如果 (errno == ENOEXEC)
            {
                /* 计算参数。 */
                int argc = 0;
                while (argv[argc++])
                size_t len = (argc + 1) * sizeof(char *);
                字符**script_argv;
                无效* ptr = NULL;
                如果 (__libc_use_alloca(len))
                    script_argv = 分配(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是一个简单的函数,它添加/bin/sh到参数列表的前面,与通过 glibc 向用户空间公开的函数__execve相同。execve

有其他人在 Linux 上遇到过这个问题吗?在我尝试过的其他所有系统上,此行为都是正确的。

答案1

好吧,我发现了问题所在。编译x.c可执行文件后,我运行ldd它,发现有一个liboit.so动态链接到可执行文件的库。这个库是由ObserveIT Unix 审计员,它会拦截已登录用户的所有活动,包括系统调用。但是,我认为仅仅拦截系统调用不会导致观察到的行为,因为重新执行是/bin/sh在 glibc 内部完成的。也许 ObserveIT 也模拟了 POSIX 函数,在这种情况下显然不符合要求。

相关内容