3

We have two RHEL 6 systems that are running identical versions of the kernel and glibc (glibc–2.12–1.90.el6_3.6). According to the POSIX standard and the Linux man pages, if the kernel determines that an executable file is not in an executable format such as ELF and it doesn't have a shebang (#!) line, the functions execl, execlp, execle, execv, execvp, and execvpe (but not execve) will attempt to execute that file using a POSIX shell, which on Linux is /bin/sh.

However, on one of the systems, executing a shell script whose first line is : using the function execvp fails, while on the other machine the script is executed using /bin/sh, as expected. Specifically, we're using these test programs; /tmp/test_script is made executable:

x.c:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

extern char **environ;

int main () {
        char *argv[]   = { "/tmp/test_script", NULL };
        char *progname = argv[0];
        if (execvp(progname, argv) == -1) {
                perror("execvp");
                return -1;
        }
}

/tmp/test_script:

:

echo "Test script called"
exit 0

We've searched the source RPM for the installed version of glibc, and it definitely implements the desired behavior (execvp is a trivial wrapper around execvpe):

posix/execvpe.c:

if (strchr(file, '/') != NULL)
    {
        /* Don't search when it contains a slash.  */
        __execve(file, argv, envp);

        if (errno == ENOEXEC)
            {
                /* Count the arguments.  */
                int argc = 0;
                while (argv[argc++])
                    ;
                size_t len = (argc + 1) * sizeof(char *);
                char **script_argv;
                void *ptr = NULL;
                if (__libc_use_alloca(len))
                    script_argv = alloca(len);
                else
                    script_argv = ptr = malloc(len);

                if (script_argv != NULL)
                    {
                        scripts_argv(file, argv, argc, script_argv);
                        __execve(script_argv[0], script_argv, envp);

                        free(ptr);
                    }
            }
    }
else
   ︙

Here, scripts_argv is a simple function that prepends /bin/sh to the argument list, and __execve is identical to the execve that is exposed to userspace via glibc.

Has anyone else encountered this issue on Linux? The behavior is correct on every other system I've tried it on.

1
  • please show the error messages. Also, use "strace -f ...." to help in finding out what's going on? Jan 3, 2013 at 18:49

1 Answer 1

0

Alright, I discovered what was calling the issue. After compiling the x.c executable, I ran ldd on it and discovered that there was a library liboit.so dynamically linked to the executable. This library was installed by the ObserveIT Unix Auditor, which intercepts all activity by logged-in users, including system calls. However, I would think that just intercepting system calls wouldn't result in the observed behavior, since the re-execution with /bin/sh is done inside glibc. Perhaps ObserveIT also emulates POSIX functions as well, apparently non-conformantly in this situation.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .