Take the 2-minute tour ×
Super User is a question and answer site for computer enthusiasts and power users. It's 100% free, no registration required.

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.

share|improve this question
    
please show the error messages. Also, use "strace -f ...." to help in finding out what's going on? –  Olivier Dulac Jan 3 '13 at 18:49

1 Answer 1

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.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.