3

У нас есть две системы RHEL 6, в которых работают идентичные версии ядра и glibc (glibc – 2.12–1.90.el6_3.6). Согласно стандарту POSIX и справочным страницам Linux, если ядро определяет, что исполняемый файл не в исполняемом формате, таком как ELF, и у него нет шебанга (#!) line, функции execl , execlp , execle , execv , execvp и execvpe (но не execve) будут пытаться выполнить этот файл с помощью оболочки POSIX, которая в Linux называется /bin/sh .

Однако в одной из систем выполнение сценария оболочки, первая строка которого : использование функции execvp завершается ошибкой, в то время как на другой машине сценарий выполняется с использованием /bin/sh , как и ожидалось. В частности, мы используем эти тестовые программы; /tmp/test_script сделан исполняемым:

хс:

#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

Мы искали в исходной RPM установленную версию glibc, и она определенно реализует желаемое поведение (execvp - тривиальная оболочка вокруг 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
   ︙

Здесь scripts_argv - это простая функция, которая добавляет /bin/sh в список аргументов, а __execve идентична execve , доступному для пространства пользователя через glibc.

Кто-нибудь еще сталкивался с этой проблемой в Linux? Поведение корректно в любой другой системе, на которой я его пробовал.

1 ответ1

0

Хорошо, я обнаружил, что вызывает проблему. После компиляции исполняемого файла x.c я запустил на нем ldd и обнаружил, что существует библиотека liboit.so динамически связанная с исполняемым файлом. Эта библиотека была установлена ObservIT Unix Auditor, который перехватывает все действия вошедших в систему пользователей, включая системные вызовы. Однако я думаю, что простое перехватывание системных вызовов не приведет к наблюдаемому поведению, поскольку повторное выполнение с /bin/sh выполняется внутри glibc. Возможно, ObserveIT также эмулирует функции POSIX, по-видимому, не в этой ситуации.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .