execve

Autres langues

Langue: fr

Version: 4 septembre 2006 (mandriva - 01/05/08)

Section: 2 (Appels système)

NOM

execve - Exécuter un programme

SYNOPSIS

#include <unistd.h>

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

DESCRIPTION

execve() exécute le programme correspondant au fichier. Celui-ci doit être un exécutable binaire ou bien un script commençant par une ligne du type :
 #! interpréteur [arg-optionel]
 

Pour plus de détails sur ce dernier cas, voir « Scripts d'interprétation » plus loin.

argv est un tableau de chaînes d'arguments passées au nouveau programme. envp est un tableau de chaînes, ayant par convention la forme cle=valeur, qui sont passées au nouveau programme comme environnement. argv ainsi que envp doivent se terminer par un pointeur NULL. Les arguments et l'environnement sont accessibles par le nouveau programme dans sa fonction principale, lorsqu'elle est définie comme :

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

En cas de réussite, execve() ne revient pas à l'appelant, et les segments de texte, de données, ainsi que la pile du processus appelant sont remplacés par ceux du programme chargé.

Si l'on effectuait un ptrace(2) sur le programme appelant, un signal SIGTRAP est envoyé après la réussite de execve().

Si le bit Set-UID est positionné sur le fichier du programme, et si le système de fichiers sous-jacent n'est pas monté avec l'option nosuid (l'attribut MS_NOSUID pour mount(2)), et si le processus appelant n'est pas tracé par ptrace(2), l'UID effectif du processus appelant est modifié pour prendre celui du propriétaire du fichier. De même, lorsque le bit Set-GID est positionné, le GID effectif est modifié pour correspondre à celui du groupe du fichier.

L'UID effectif du processus est copié dans le Set-UID sauvé ; de la même manière, le GID effectif est copié dans le Set-GID sauvé. Ces copies ont lieu après toute modification d'ID effectif à cause des bits de permissions Set-UID et Set-GID.

Si l'exécutable est un fichier binaire a.out lié dynamiquement, et contenant des appels aux bibliothèques partagées, le linker dynamique de Linux ld.so(1) est appelé avant l'exécution, afin de charger les bibliothèques partagées nécessaires en mémoire, et d'effectuer l'édition des liens de l'exécutable.

Si l'exécutable est au format ELF lié dynamiquement, l'interpréteur indiqué dans le segment PT_INTERP sera invoqué pour charger les bibliothèques partagées. Cet interpréteur est généralement /lib/ld-linux.so.1 pour les fichiers binaires liés avec la libc Linux version 5, ou /lib/ld-linux.so.2 pour ceux liés avec la GNU libc version 2.

Tous les attributs d'un processus sont conservés pendant un execve(), à l'exeption des suivants :

*
L'ensemble des signaux en suspens est effacé (sigpending(2)).
*
Les dispositions de tous les signaux qui ont été capturés sont réinitialisées afin d'être ignorées.
*
Les piles spécifiques de signaux ne sont pas conservées. (sigaltstack(2)).
*
Les projections mémoire ne sont pas conservées. (mmap(2)).
*
Les segments de mémoire partagée « System V » attachés sont détachés. (shmat(2)).
*
Les régions de mémoire partagée POSIX sont déprojetées. (shm_open(3)).
*
Les descripteurs de file de messages ouverts sont fermés (mq_overview(7)).
*
Les sémaphores nommés POSIX ouverts sont fermés (sem_overview(7)).
*
Les temporisateurs POSIX ne sont pas conservés (timer_create(3)).
*
Les flux de répertoire ouverts sont fermés (opendir(3)).
*
Les verrous mémoire ne sont pas conservés (mlock(2), mlockall(2)).
*
Les gestionnaires de sortie ne sont pas conservés (atexit(3), on_exit(3)).

Les attributs de processus de la liste précédente sont tous spécifiés dans POSIX.1-2001. Les attributs de processus, spécifiques à Linux, suivants ne sont pas conservés pendant un execve():

*
L'attribut PR_SET_DUMPABLE de prctl(2) est positionné, à moins qu'un programme SUID ou SGID ait été exécuté, auquel cas il est effacé.
*
L'attribut PR_SET_KEEPCAPS de prctl(2) est effacé.
*
Le nom du processus, tel que défini par prctl(2) PR_SET_NAME (et affiché avec ps -o comm), est réinitialisé avec le nom du nouveau fichier exécutable.
*
Le signal de termimaison est réinitialisé à SIGCHLD (voir clone(2)).

Veuillez noter les points suivants :

*
Tous les threads autre que le thread appelant sont détruits lors d'un execve(). Les mutexes, les variables de condition et autres objets pthreads ne sont pas conservés.
*
L'équivalent de setlocale(LC_ALL, "C") est exécuté au démarrage du programme.
*
POSIX.1-2001 spécifie que les dispositions des signaux qui sont soit ignorés, soit définies à leur valeur par défaut, ne sont pas modifiées. POSIX.1-2001 spécifie une exception : si SIGCHLD est ignoré, une implémentation peut laisser la disposition inchangée ou bien la réinitialiser à sa valeur par défaut ; Linux fait le premier.
*
Les opérations d'E/S asynchrones non exécutées sont annulées. (aio_read(3), aio_write(3)).
*
Pour la gestion des capacités lors d'un execve(2), voir capabilities(7).
*
Par défaut, les descripteurs de fichiers restent ouverts au travers d'un execve(). Les descripteurs de fichiers marqués « close-on-exec » sont fermés ; voir la description de FD_CLOEXEC dans fcntl(2). (Si un descripteur de fichier est fermé, cela entrainera la libération de tous les verrous d'enregistrement obtenus sur le fichier sous-jacent par ce processus. Voir fcntl(2) pour les détails.) POSIX.1-2001 dit que si les descripteurs de fichiers 0, 1 et 2 devraient être fermés après un appel réussi à execve(), et le processus devient privilégié parce que le bit SUID ou SGID est positionné sur le fichier exécuté, le système peut ouvrir un fichier non spécifié pour chacun de ces descripteurs. En général, aucun programme portable, privilégié ou non, ne peut considérer que ces trois descripteurs de fichiers resteront fermés après un execve().

Scripts d'interprétation

Un script d'interprétation est un fichier texte qui a son bit d'exécution activé et dont la première ligne est de la forme :
 #! interpréteur [arg-optionel]
 

L'interpréteur doit être indiqué par un nom complet, avec son chemin d'accès, et ne doit pas être lui-même un script. Si l'argument fichier de execve() spécifie un script, l'interpréteur sera invoqué avec les arguments suivants :

 interpréteur [arg-optionel] fichier arg...
 

arg... est une série de mots pointés par l'argument argv de execve().

Pour une utilisation portable, arg-optionel doit être soit absent, soit être un mot unique (c'est-à-dire ne pas contenir d'espace) ; voir NOTES plus loin.

VALEUR RENVOYÉE

En cas de réussite, execve() ne revient pas, en cas d'échec il renvoie -1 et errno contient le code d'erreur.

ERREURS

E2BIG
Le nombre total d'octets dans l'environnement (envp) et dans la liste d'arguments (argv) est trop grang
EACCES
La permission de parcours est refusée pour un des composants du chemin filename ou du nom d'un interpréteur de script. (Voir aussi path_resolution(7).)
EACCES
Le fichier n'est pas un fichier régulier.
EACCES
L'autorisation d'exécution est refusée pour le fichier, ou un script, ou un interpréteur ELF.
EACCES
Le système de fichiers est monté avec l'option noexec.
EFAULT
L'argument fichier pointe en dehors de l'espace d'adressage accessible.
EINVAL
Un exécutable ELF a plusieurs segments PT_INTERP (indique plusieurs interpréteurs).
EIO
Une erreur d'entrée-sortie de bas niveau s'est produite.
EISDIR
L'interpréteur ELF cité est un répertoire.
ELIBBAD
L'interpréteur ELF mentionné n'est pas dans un format connu.
ELOOP
Le chemin d'accès au fichier contient une référence circulaire (à travers un lien symbolique)
EMFILE
Le nombre maximal de fichiers ouverts par processus est atteint.
ENAMETOOLONG
La chaîne de caractères fichier est trop longue.
ENFILE
La limite du nombre total de fichiers ouverts sur le système est atteinte.
ENOENT
Le fichier ou un script ou un interpréteur ELF n'existe pas, ou une bibliothèque partagée nécessaire pour le fichier ou l'interpréteur n'est pas disponible.
ENOEXEC
Le fichier exécutable n'est pas dans le bon format, ou est destiné à une autre architecture.
ENOMEM
Pas assez de mémoire pour le noyau.
ENOTDIR
Un élément du chemin d'accès n'est pas un répertoire.
EPERM
Le système de fichiers est monté avec l'attribut nosuid et le fichier a un bit Set-UID ou Set-GID positionné.
EPERM
Le processus est suivi avec ptrace(2), l'utilisateur n'est pas le superutilisateur, et le fichier a un bit Set-UID ou Set-GID activé.
ETXTBSY
Le fichier exécutable a été ouvert en écriture par un ou plusieurs processus.

CONFORMITÉ

SVr4, BSD 4.3, POSIX.1-2001. POSIX.1-2001 ne documente pas le comportement avec #! mais est néanmoins compatible.

NOTES

Les processus Set-UID et Set-GID ne peuvent pas être suivis par ptrace(2).

Linux ignore les bits Set-UID et Set-GID sur les scripts.

Le résultat d'un montage de système de fichiers avec l'attribut nosuid peut varier suivant les versions de noyau : certaines refuseront l'exécution des fichiers SUID/SGID lorsque cela donnerait à l'appelant des privilèges qu'il n'a pas (et renverront l'erreur EPERM), d'autres ignoreront simplement les bits SUID/SGID mais accepteront d'effectuer l'appel execve().

La première ligne d'un script shell exécutable (#!) a une longueur maximale de 127 caractères.

La sémantique de l'argument arg-optionel d'un script varie suivant les implémentations. Sous Linux, la chaîne entière suivant le nom de l'interpréteur est passée à l'interpréteur comme un argument unique et la chaîne peut contenir des espaces. Toutefois, les comportements diffèrent sur d'autres systèmes. Certains systèmes utilisent la première espace pour terminer l'argument arg-optionel. Sur d'autres systèmes, le script peut avoir plusieurs arguments et les espaces dans arg-optionel sont utilisées pour délimiter les arguments.

Sous Linux, argv et envp peuvent être NULL, ce qui a le même effet que de spécifier que ces arguments sont des pointeurs vers des listes contenant un pointeur NULL unique. Ne vous servez pas de cette caractéristique ! Elle n'est ni standard, ni portable : sur la plupart des autres systèmes Unix, elle provoquera une erreur.

Historique

Avec Unix V6, la liste des arguments d'un appel exec() se terminait par 0, alors que la liste des arguments de main se terminait par -1. Aussi, cette liste d'arguments n'était pas utilisable directement dans un appel exec() supplémentaire.

EXEMPLE

Le programme suivant est conçu pour être exécuté par le second programme ci-dessous. Il affiche sa ligne de commande, un argument par ligne.
 /* 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);
 }
 

Ce programme peut être utilisé pour exécuter le programme indiqué comme argument de ligne de commande :

 
 /* execve.c */
 
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
 #include <assert.h>
 
 int
 main(int argc, char *argv[])
 {
     char *newargv[] = { NULL, "hello", "world", NULL };
     char *newenviron[] = { NULL };
 
     assert(argc == 2);  /* argv[1] identifies 
                            program to exec */
     newargv[0] = argv[1];
 
     execve(argv[1], newargv, newenviron);
     perror("execve");   /* execve() only returns on error */
     exit(EXIT_FAILURE);
 }
 

Nous pouvons utiliser le second programme pour exécuter le premier de la manière suivante :

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

Nous pouvons également utiliser ces programmes pour montrer l'utilisation d'un script. Pour ce faire, nous créons un script dont l'« interpréteur » est notre programme myecho :

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

Nous pouvons ensuite utiliser notre programme pour exécuter le script :

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

VOIR AUSSI

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

TRADUCTION

Ce document est une traduction réalisée par Christophe Blaess <http://www.blaess.fr/christophe/> le 9 octobre 1996 et révisée le 28 novembre 2007.

L'équipe de traduction a fait le maximum pour réaliser une adaptation française de qualité. La version anglaise la plus à jour de ce document est toujours consultable via la commande : « LANG=C man 2 execve ». N'hésitez pas à signaler à l'auteur ou au traducteur, selon le cas, toute erreur dans cette page de manuel.