Scroll to navigation

EXECVE(2) Linux-Programmierhandbuch EXECVE(2)

BEZEICHNUNG

execve - Programme ausführen

ÜBERSICHT

#include <unistd.h>

int execve(const char *filename, char *const argv[],
char *const envp[]);

BESCHREIBUNG

execve() führt das Programm aus, auf das filename verweist. filename muss entweder ein binäres ausführbares Programm oder ein Skript sein, das mit einer Zeile der folgenden Form beginnt:


#! Interpreter [Optionale-Arg]

Für Details über den zweiten Fall lesen Sie »Interpreter-Skripte« weiter unten.

argv ist ein Feld von Argumentenzeichenketten, die an das neue Programm übergeben werden. Per Konvention sollte die erste dieser Zeichenketten (d.h. argv[0]) den Dateinnamen, der zu der ausgeführten Datei gehört, enthalten. envp ist ein Feld von Zeichenketten, das per Konvention die Form Schlüssel=Wert haben sollte, das an die Umgebung des neuen Programms übergeben wird. Die Felder argv und envp müssen jeder einen Null-Zeiger am Ende des Feldes enthalten.

Auf den Argumentzeiger und die Umgebung kann von der Main-Funktion des aufgerufenen Programms zugegriffen werden, wenn sie wie folgt definiert ist:


int main(int argc, char *argv[], char *envp[])

Beachten Sie allerdings, dass die Verwendung eines dritten Arguments bei der Funktion main nicht in POSIX.1 spezifiziert ist; laut POSIX.1 sollte auf die Umgebung über die externe Variable environ(7) zugegriffen werden.

execve() kehrt bei Erfolg nicht zurück und Text, initialisierte Daten, uninitalisierte Daten (bss) und Stack des aufrufenden Prozesses werden entsprechend des Inhalts des neu geladenen Programms überschrieben.

If the current program is being ptraced, a SIGTRAP signal is sent to it after a successful execve().

If the set-user-ID bit is set on the program file pointed to by filename, and the underlying filesystem is not mounted nosuid (the MS_NOSUID flag for mount(2)), and the calling process is not being ptraced, then the effective user ID of the calling process is changed to that of the owner of the program file. Similarly, when the set-group-ID bit of the program file is set the effective group ID of the calling process is set to the group of the program file.

Die effektive Benutzer-ID des Prozesses wird in die gespeicherte set-user-ID kopiert. Ähnlich wird die effektive Gruppen-ID in die gespeicherte set-group-ID kopiert. Dieses Kopieren findet nach allen effektiven ID-Änderungen statt, die aufgrund der Modusbits set-user-ID und set-group-ID erfolgen.

Die echte UID und echte GID des Prozesses sowie die zusätzlichen Gruppen-IDs ändern sich beim Aufruf von execve(2) nicht.

If the executable is an a.out dynamically linked binary executable containing shared-library stubs, the Linux dynamic linker ld.so(8) is called at the start of execution to bring needed shared objects into memory and link the executable with them.

Falls das Programm ein dynamisch gelinktes ELF-Programm ist, wird der in dem Segment PT_INTERP benannte Interpreter zum Laden der gemeinsamen Objekte verwandt. Dieser Interpreter ist typischerweise /lib/ld-linux.so.2 für Programme, die mit der Glibc gelinkt sind (siehe ld-linux.so(8)).

Alle außer den nachfolgend aufgeführten Prozessattributen werden durch ein execve() erhalten:

  • The dispositions of any signals that are being caught are reset to the default (signal(7)).
  • Jeder alternative Signal-Stack wird nicht erhalten (sigaltstack(2)).
  • Memory mappings are not preserved (mmap(2)).
  • Attached System V shared memory segments are detached (shmat(2)).
  • POSIX shared memory regions are unmapped (shm_open(3)).
  • Open POSIX message queue descriptors are closed (mq_overview(7)).
  • Any open POSIX named semaphores are closed (sem_overview(7)).
  • POSIX timers are not preserved (timer_create(2)).
  • Alle offenen Verzeichnis-Streams werden geschlossen (opendir(3)).
  • Speichersperren werden nicht erhalten (mlock(2), mlockall(2)).
  • Exit handlers are not preserved (atexit(3), on_exit(3)).
  • Die Gleitkomma-Umgebung wird auf den Standardwert zurückgesetzt (siehe fenv(3)).

Die Prozessattribute in der vorstehenden Liste sind alle in POSIX.1 spezifiziert. Die folgenden Linux-spezifischen Prozessattribute werden auch während eines execve() nicht erhalten:

  • Der prctl(2)-Schalter PR_SET_DUMPABLE wird gesetzt. Wird ein set-user-ID- oder set-group-ID-Programm ausgeführt, dann wird er zurückgesetzt.
  • Der prctl(2)-Schalter PR_SET_KEEPCAPS wird zurückgesetzt.
  • (Since Linux 2.4.36 / 2.6.23) If a set-user-ID or set-group-ID program is being executed, then the parent death signal set by prctl(2) PR_SET_PDEATHSIG flag is cleared.
  • Der Prozessname, wie er von prctl(2) PR_SET_NAME gesetzt (und durch ps -o comm angezeigt) wird, wird auf den Namen des ausführbaren Programms zurückgesetzt.
  • Der SECBIT_KEEP_CAPS Schalter securebits wird zurückgesetzt. Siehe capabilities(7).
  • Das Terminierungssignal wird auf SIGCHLD zurückgesetzt (siehe clone(2)).
  • Die Dateideskriptortabelle wird getrennt, der Effekt des Schalters CLONE_FILES von clone(2) wird rückgängig gemacht.

Beachten Sie die weiteren folgenden Punkte:

  • All threads other than the calling thread are destroyed during an execve(). Mutexes, condition variables, and other pthreads objects are not preserved.
  • Das Äquivalent von setlocale(LC_ALL, "C") wird beim Programmstart ausgeführt.
  • POSIX.1 specifies that the dispositions of any signals that are ignored or set to the default are left unchanged. POSIX.1 specifies one exception: if SIGCHLD is being ignored, then an implementation may leave the disposition unchanged or reset it to the default; Linux does the former.
  • Alle ausstehenden asynchronen E/A-Operationen werden abgebrochen (aio_read(3), aio_write(3)).
  • Für den Umgang mit Capabilities während execve(), siehe capabilities(7).
  • By default, file descriptors remain open across an execve(). File descriptors that are marked close-on-exec are closed; see the description of FD_CLOEXEC in fcntl(2). (If a file descriptor is closed, this will cause the release of all record locks obtained on the underlying file by this process. See fcntl(2) for details.) POSIX.1 says that if file descriptors 0, 1, and 2 would otherwise be closed after a successful execve(), and the process would gain privilege because the set-user-ID or set-group_ID mode bit was set on the executed file, then the system may open an unspecified file for each of these file descriptors. As a general principle, no portable program, whether privileged or not, can assume that these three file descriptors will remain closed across an execve().

Interpreter-Skripte

Ein Interpreter-Skript ist eine Textdatei, die über Ausführrechte verfügt und dessen erste Zeile die folgende Form annimmt:


#! Interpreter [Optionale-Arg]

Der interpreter muss ein gültiger Pfadname für eine ausführbare Datei sein. Falls das Argument filename von execve() ein Interpreterskript festlegt, dann wird interpreter mit den folgenden Argumenten aufgerufen.


Interpreter [Optionale-Arg] filename Arg …

wobei Arg… eine Reihe von Wörtern ist, auf die vom Arugment argv von execve() gezeigt wird, beginnend bei argv[1].

Für den portablen Einsatz sollte Optionale-Arg entweder abwesend oder als einzelnes Wort festgelegt werden (d.h. es sollte keine Leerraumzeichen enthalten); siehe ANMERKUNGEN unten.

Seit Linux 2.6.28 erlaubt es der Kernel, dass der Interpreter eines Skripts selbst wieder ein Skript ist. Diese Erlaubnis ist rekursiv bis zu einer Rekursionstiefe von 4, so dass der Interpreter ein Skript sein darf, das von einem Skript interpretiert wird und so weiter.

Begrenzungen der Größe der Argumente und der Umgebung

Die meisten UNIX-Implementierungen verhängen eine Begrenzung für die Gesamtgröße der Zeichenketten der Befehlszeilenargumente (argv) und der Umgebung (envp), die an ein neues Programm übergeben werden darf. POSIX.1 erlaubt es einer Implementierung, diese Begrenzung mit der Konstante ARG_MAX bekanntzugeben (entweder definiert in <limits.h> oder zur Laufzeit mit dem Aufruf sysconf(_SC_ARG_MAX) verfügbar).

Vor Kernel 2.6.23 unter Linux war der Speicher, der zum Ablegen der Umgebungs- und Argumentzeichenketten verwandt wurde auf 32 Seiten begrenzt (definiert durch die Kernelkonstante MAX_ARG_PAGES). Auf Architekturen mit einer 4-kB-Seitengröße führt dies zu einer Maximalgröße von 128 kB.

On kernel 2.6.23 and later, most architectures support a size limit derived from the soft RLIMIT_STACK resource limit (see getrlimit(2)) that is in force at the time of the execve() call. (Architectures with no memory management unit are excepted: they maintain the limit that was in effect before kernel 2.6.23.) This change allows programs to have a much larger argument and/or environment list. For these architectures, the total size is limited to 1/4 of the allowed stack size. (Imposing the 1/4-limit ensures that the new program always has some stack space.) Since Linux 2.6.25, the kernel places a floor of 32 pages on this size limit, so that, even when RLIMIT_STACK is set very low, applications are guaranteed to have at least as much argument and environment space as was provided by Linux 2.6.23 and earlier. (This guarantee was not provided in Linux 2.6.23 and 2.6.24.) Additionally, the limit per string is 32 pages (the kernel constant MAX_ARG_STRLEN), and the maximum number of strings is 0x7FFFFFFF.

RÜCKGABEWERT

Im Erfolgsfall kehrt execve() nicht zurück, im Fehlerfall wird -1 zurückgeliefert und errno entsprechend gesetzt.

FEHLER

E2BIG
Die Gesamtanzahl von Bytes in der Umgebungs- (envp) und der Argumentenliste (argv) ist zu groß.
EACCES
Für einen Teil des Pfadpräfixes von filename oder dem Namen des Skript-Interpreters wird die Suchberechtigung verweigert. (Siehe auch path_resolution(7).)
EACCES
Die Datei oder der Skriptinterpreter ist keine reguläre Datei.
EACCES
Für die Datei oder ein Skript oder ELF-Interpreter wird die Ausführberechtigung verweigert.
EACCES
Das Dateisystem ist nicht noexec eingehängt.
EAGAIN (seit Linux 3.1)
Nach Änderung der echten UID mittels einer der Aufrufe set*uid() war – und ist immer noch – der Aufrufende über seine Ressourcenbegrenzung RLIMIT_NPROC (siehe setrlimit(2)). Für eine detailliertere Erläuterung dieses Fehlers siehe ANMERKUNGEN.
EFAULT
filename oder einer der Zeiger in den Vektoren argv oder envp zeigt aus dem für Sie zugänglichen Adressraum heraus.
EINVAL
Ein ELF-Programm hat mehr als ein PT_INTERP-Segment (d.h. versuchte mehr als einen Interpreter anzugeben).
EIO
Es ist ein E/A-Fehler (engl. I/O) aufgetreten.
EISDIR
Ein ELF-Interpreter war ein Verzeichnis.
ELIBBAD
Ein ELF-Interpreter war in einem unbekannten Format.
ELOOP
Beim Auflösen von filename oder dem Namen eines Skripts oder ELF-Interpreters wurden zu viele symbolische Links ermittelt.
ELOOP
Während der rekursiven Skript-Interpretation (siehe »Interpreter-Skripte« oben) wurde die maximale Rekursionsbegrenzung erreicht. Vor Linux 3.8 wurde in diesem Fall der Fehler ENOEXEC erstellt.
EMFILE
Die Beschränkung pro-Prozess der Anzahl offener Datei-Deskriptoren wurde erreicht.
ENAMETOOLONG
filename ist zu lang.
ENFILE
Die systemweite Beschränkung für die Gesamtzahl offener Dateien wurde erreicht.
ENOENT
Die Datei filename oder ein Skript oder ein ELF-Interpreter existiert nicht oder eine Laufzeitbibliothek, die für die Datei oder den Interpreter benötigt wird, kann nicht gefunden werden.
ENOEXEC
Ein Programm ist nicht in einem erkennbaren Format, ist für die falsche Architektur oder hat einen anderen Formatfehler, wodurch es nicht ausgeführt werden kann.
ENOMEM
Es war nicht genügend Kernel-Speicher verfügbar.
ENOTDIR
Ein Teil des Pfadpräfixes von filename oder ein Skript oder ELF-Interpreter ist kein Verzeichnis.
EPERM
Das Dateisystem ist nosuid eingehängt, der Benutzer ist nicht der Superuser und die Datei hat das Bit set-user-ID oder Bit set-group-ID gesetzt.
EPERM
The process is being traced, the user is not the superuser and the file has the set-user-ID or set-group-ID bit set.
EPERM
Eine »Capability-unfähige« Anwendung würde nicht die die Menge der vom ausführbaren Programm gewährten erlaubten Capabilities erhalten. Siehe capabilities(7).
ETXTBSY
Das angegebene Programm war für einen oder mehrere Prozesse zum Schreiben offen.

KONFORM ZU

POSIX.1-2001, POSIX.1-2008, SVr4, 4.3BSD. POSIX dokumentiert das #!-Verhalten nicht, es existiert aber (mit einigen Variationen) auf anderen UNIX-Systemen.

ANMERKUNGEN

Set-user-ID and set-group-ID processes can not be ptrace(2)d.

Das Ergebnis des Einhängens eine Dateisystem mit nosuid unterscheidet sich abhängig von der Linux-Kernelversion. Unter einigen wird die Ausfühnrung von Programmen mit set-user-ID und set-group-ID verweigert, wenn das dem Benutzer Rechte geben würde, die er noch nicht bereits hatte (und EPERM zurückliefern). Unter anderen werden die Bits set-user-ID und set-group-ID ignoriert und exec() erfolgreich ausgeführt.

Unter Linux können argv und envp als NULL festgelegt werden. In beiden Fällen hat dies den gleichen Effekt wie die Festlegung des Arguments auf einen Zeiger auf eine Liste, die als einziges Element den NULL-Zeiger enthält. Nutzen Sie diese nicht standardisierte und nicht portable Misfunktionalität nicht aus! Unter vielen UNIX-Systemen führt die Festlegung von argv als NULL zu einem Fehler (EFAULT). Einige andere UNIX-Systeme behandeln den Fall envp==NULL wie Linux.

POSIX.1 besagt, dass die von sysconf(3) zurückgelieferten Werte über die Lebensdauer eines Prozesses unveränderlich sein sollen. Seit 2.6.23 wird der von _SC_ARG_MAX berichtete Wert sich allerdings auch ändern, wenn die Ressourcenbegrenzung RLIMIT_STACK sich ändert, um die Tatsache zu berücksichtigen, dass die Begrenzung des Platzes zum Halten der Befehlszeilenargumente und der Umgebungsvariablen sich geändert hat.

In den meisten Fällen, in denen execve() fehlschlägt, kehrt die Steuerung zu dem ursprünglichen Abbild zurück und der Aufrufende von execve() kann mit dem Fehler umgehen. In (seltenen) Fällen kann (typischerweise durch Ressourcenerschöpfung verursacht) der Fehlschlag den Punkt ohne Rückkehr passieren: das ursprüngliche Abbild wurde bereits entfernt aber das neue Abbild konnte nicht komplett gebaut werden. In diesen Fällen beendet der Kernel den Prozess mit einem Signal SIGKILL.

Interpreter-Skripte

Eine maximale Zeilenlänge von 127 Zeichen wird für die erste Zeile in einem interpretierten Skript.

Die Semantik des Arguments Optionale-Args eines Interpreterskriptes unterscheidet sich zwischen Implementierungen. Unter Linux wird die gesamte Zeichenkette, die Interpreter folgt, als einziges Argument an den Interpreter übergeben und diese Zeichenkette kann Leerzeichen enthalten. Das Verhalten unterscheidet sich aber auf einigen anderen Systemen. Einige Systeme verwenden das erste Leerzeichen, um Optionale-Args zu beenden. Auf einigen Systemen kann ein Interpreterskript mehrere Argumente haben und Leerzeichen in Optionale-Args werden zum Begrenzen der Argumente verwandt.

Linux ignoriert die Bits »set-user-ID« und »set-group-ID« bei Skripten.

execve() und EAGAIN

Eine detailliertere Beschreibung des Fehlers EAGAIN, der (seit Linux 3.1) beim Aufruf von execve() auftreten kann, ist wie folgt:

Der Fehler EAGAIN kann auftreten, wenn ein vorhergehender Aufruf von setuid(2), setreuid(2) oder setresuid(2) dazu führte, dass die echte Benutzer-ID des Prozesses geändert wurde und diese Änderung dazu führte, dass der Prozess seine Ressourcenbeschränkung RLIMIT_NPROC überschritt (d.h. die Anzahl der zu der neuen echten UID gehörenden Prozesse überschreitet die Ressourcenbeschränkung). Von Linux 2.6.0 bis 3.0 führte dies dazu, dass der Aufruf set*uid() fehlschlug. (Vor 2.6 wurde die Ressourcenbeschränkung bei Prozessen, die ihre Benutzer-IDs änderten, nicht durchgesetzt.)

Seit Linux 3.1 schlägt in dem gerade beschriebenen Szenario der Aufruf set*uid() nicht mehr fehl, da dies zu oft zu Sicherheitslöchern führte, bei denen fehlerhafte Anwendungen nicht den Rückgabewert prüften und annahmen, dass – falls der Aufrufende Root-Rechte hatte – der Aufruf immer erfolgreich sein würde. Stattdessen ändert der Aufruf set*uid() jetzt erfolgreich die echte UID, aber der Kernel setzt einen internen Schalter namens PF_NPROC_EXCEEDED, um zu vermerken, dass die Ressourcenbeschränkung RLIMIT_NPROC überschritten wurde. Falls der Schalter PF_NPROC_EXCEEDED gesetzt ist und die Ressourcenbeschränkung zum Zeitpunkt eines folgenden execve()-Aufrufs immer noch überschritten ist, dann schlägt dieser Aufruf mit dem Fehler EAGAIN fehl. Diese Kernellogik stellt sicher, dass die Ressourcenbeschränkung RLIMIT_NPROC für den häufigen Ablauf bei privilegierten Daemons – also fork(2) + set*uid() + execve() – weiterhin durchgesetzt wird.

Falls die Ressourcenbegrenzung zum Zeitpunkt des Aufrufs execve() noch nicht überschritten wurde (da andere zu dieser echten UID gehörende Prozesse sich zwischen dem Aufruf von set*uid() und dem Aufruf von execve() beendeten) dann gelingt der Aufruf und der Kernel bereinigt den Prozessschalter PF_NPROC_EXCEEDED. Der Schalter wird auch bereinigt, falls ein folgender Aufruf von fork(2) durch diesen Prozess gelingt.

Historisches

Unter UNIX V6 wurde die Argumentenliste von einem exec()-Aufruf durch 0 beendet, während die Argumentenliste von main durch -1 beendet wurde. Daher war diese Argumentenliste nicht für weitere exec()-Aufrufe direkt verwendbar. Seit UNIX V7 sind beide NULL.

BEISPIEL

Das folgende Programm ist dafür gedacht, vom zweiten folgenden Programm ausgeführt zu werden. Es gibt nur seine Befehlszeile (eine pro Zeile) wieder aus.


/* myecho.c */
#include <stdio.h>
#include <stdlib.h>
int
main(int argc, char *argv[])
{
    int j;
    for (j = 0; j < argc; j++)
        printf("argv[%d]: %s\n", j, argv[j]);
    exit(EXIT_SUCCESS);
}

Dieses Programm kann zur Ausführung des in seinem Befehlszeilenargument benannten Programms verwandt werden:

/* execve.c */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int
main(int argc, char *argv[])
{
    char *newargv[] = { NULL, "hello", "world", NULL };
    char *newenviron[] = { NULL };
    if (argc != 2) {
	printf(stderr, "Aufruf: %s <auszuführende-Datei>\n", argv[0]);
	exit(EXIT_FAILURE);
    }
    newargv[0] = argv[1];
    execve(argv[1], newargv, newenviron);
    perror("execve");   /* execve() kehrt nur im Fehlerfall zurück */
    exit(EXIT_FAILURE);
}

Wir können das zweite Programm verwenden, um das erste wie folgt aufzurufen:


$ cc myecho.c -o myecho
$ cc execve.c -o execve
$ ./execve ./myecho
argv[0]: ./myecho
argv[1]: hello
argv[2]: world

Wir können diese Programme auch zur Demonstration der Verwendung eines Skript-Interpreters verwenden. Dafür erstellen wir ein Skript, dessen »Interpreter« unser myecho-Programm ist.


$ cat > script
#!./myecho script-arg
^D
$ chmod +x script

Wir können dann unser Program verwenden, um das Skript auszuführen:


$ ./execve ./script
argv[0]: ./myecho
argv[1]: script-arg
argv[2]: ./script
argv[3]: hello
argv[4]: world

SIEHE AUCH

chmod(2), execveat(2), fork(2), ptrace(2), execl(3), fexecve(3), getopt(3), system(3), credentials(7), environ(7), path_resolution(7), ld.so(8)

KOLOPHON

Diese Seite ist Teil der Veröffentlichung 4.09 des Projekts Linux-man-pages. Eine Beschreibung des Projekts, Informationen, wie Fehler gemeldet werden können sowie die aktuelle Version dieser Seite finden sich unter https://www.kernel.org/doc/man-pages/.

ÜBERSETZUNG

Die deutsche Übersetzung dieser Handbuchseite wurde von Helge Kreutzmann <debian@helgefjell.de> erstellt.

Diese Übersetzung ist Freie Dokumentation; lesen Sie die GNU General Public License Version 3 oder neuer bezüglich der Copyright-Bedingungen. Es wird KEINE HAFTUNG übernommen.

Wenn Sie Fehler in der Übersetzung dieser Handbuchseite finden, schicken Sie bitte eine E-Mail an <debian-l10n-german@lists.debian.org>.

8. Oktober 2016 Linux