execvp-Exec-Formatfehler für Shell-Skript unter Red Hat Enterprise Linux 6

execvp-Exec-Formatfehler für Shell-Skript unter Red Hat Enterprise Linux 6

Wir haben zwei RHEL 6-Systeme, auf denen identische Versionen des Kernels und von glibc (glibc–2.12–1.90.el6_3.6) laufen. Laut POSIX-Standard und den Linux-Manpages gilt: Wenn der Kernel feststellt, dass eine ausführbare Datei nicht in einem ausführbaren Format wie ELF vorliegt und keine Shebang( #!)-Zeile hat, versuchen die Funktionen execl, execlp, execle, execv, execvp, und execvpe(aber nicht execve), diese Datei mit einer POSIX-Shell auszuführen, was unter Linux der Fall ist /bin/sh.

Auf einem der Systeme schlägt jedoch die Ausführung eines Shell-Skripts fehl, dessen erste Zeile :die Funktion verwendet execvp, während auf dem anderen Rechner das Skript wie erwartet mit ausgeführt wird /bin/sh. Konkret verwenden wir diese Testprogramme; /tmp/test_scriptausführbar gemacht wird:

xc:

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

externer Zeichen **Umgebung;

int haupt () {
        char *argv[] = { "/tmp/test_script", NULL };
        char *Programmname = argv[0];
        wenn (execvp(Programmname, argv) == -1) {
                perror("execvp");
                Rückgabe -1;
        }
}

/tmp/test_script:

:

echo "Testskript aufgerufen"
Ausfahrt 0

Wir haben im Quell-RPM nach der installierten Version von glibc gesucht und es implementiert definitiv das gewünschte Verhalten (execvp ist ein trivialer Wrapper um execvpe):

posix/execvpe.c:

wenn (strchr(Datei, '/') != NULL)
    {
        /* Nicht suchen, wenn ein Schrägstrich enthalten ist. */
        __execve(Datei, argv, envp);

        wenn (errno == ENOEXEC)
            {
                /* Zähle die Argumente. */
                argc = 0;
                während (argv[argc++])
                    ;
                size_t Länge = (argc + 1) * Größe von (Zeichen *);
                Zeichen **Skriptargv;
                void *ptr = NULL;
                wenn (__libc_use_alloca(Länge))
                    script_argv = alloca(Länge);
                anders
                    script_argv = ptr = malloc(Länge);

                wenn (script_argv != NULL)
                    {
                        scripts_argv(Datei, argv, argc, script_argv);
                        __execve(Skriptargv[0], Skriptargv, envp);

                        frei(ptr);
                    }
            }
    }
anders
   ︙

Dies scripts_argvist eine einfache Funktion, die /bin/shder Argumentliste vorangestellt wird und __execvemit der Funktion identisch ist execve, die dem Benutzerbereich über glibc zur Verfügung gestellt wird.

Ist dieses Problem bei anderen unter Linux aufgetreten? Auf allen anderen Systemen, auf denen ich es ausprobiert habe, ist das Verhalten korrekt.

Antwort1

Okay, ich habe herausgefunden, was das Problem verursacht hat. Nachdem ich die x.causführbare Datei kompiliert hatte, habe ich lddsie ausgeführt und festgestellt, dass eine Bibliothek liboit.sodynamisch mit der ausführbaren Datei verknüpft war. Diese Bibliothek wurde vomObserveIT Unix Auditor, das alle Aktivitäten angemeldeter Benutzer abfängt, einschließlich Systemaufrufen. Ich würde jedoch denken, dass das bloße Abfangen von Systemaufrufen nicht zu dem beobachteten Verhalten führen würde, da die erneute Ausführung /bin/shinnerhalb von glibc erfolgt. Vielleicht emuliert ObserveIT auch POSIX-Funktionen, in dieser Situation offenbar nicht konform.

verwandte Informationen