execvp erro no formato exec para o shell script no Red Hat Enterprise Linux 6

3

Temos dois sistemas RHEL 6 que executam versões idênticas do kernel e da glibc (glibc – 2.12–1.90.el6_3.6). De acordo com o padrão POSIX e as man pages do Linux, se o kernel determinar que um arquivo executável não está em um formato executável como o ELF e não possui uma linha shebang ( #! ), as funções execl , execlp , execle , execv , execvp e execvpe (mas não execve ) tentarão executar esse arquivo usando um shell POSIX, que no Linux é /bin/sh .

No entanto, em um dos sistemas, executar um script de shell cuja primeira linha é : usando a função execvp falha, enquanto na outra máquina o script é executado usando /bin/sh , como esperado. Especificamente, estamos usando esses programas de teste; /tmp/test_script é feito como executável:

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

Pesquisamos o RPM de origem para a versão instalada do glibc e ele implementa definitivamente o comportamento desejado (o execvp é um wrapper trivial em torno do 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
   ︙

Aqui, scripts_argv é uma função simples que pré-acrescenta /bin/sh à lista de argumentos, e __execve é idêntico ao execve que é exposto ao espaço do usuário via glibc.

Alguém mais encontrou esse problema no Linux? O comportamento está correto em todos os outros sistemas em que eu experimentei.

    
por telotortium 03.01.2013 / 19:45

1 resposta

0

Tudo bem, descobri o que estava chamando o problema. Depois de compilar o executável x.c , executei ldd nele e descobri que havia uma biblioteca liboit.so dinamicamente vinculada ao executável. Esta biblioteca foi instalada pelo ObserveIT Unix Auditor , que intercepta todas as atividades dos usuários logados, incluindo as chamadas do sistema. No entanto, eu pensaria que apenas interceptar as chamadas do sistema não resultaria no comportamento observado, uma vez que a reexecução com /bin/sh é feita dentro da glibc. Talvez o ObserveIT também emule funções do POSIX, aparentemente sem conformação nesta situação.

    
por 07.01.2013 / 06:39