Processus & Threads · Section 2
execve(2)
Remplace l'image du processus courant par un nouveau programme.
Signature
#include <unistd.h>
int execve(const char * pathname, char *const [] argv, char *const [] envp);- pathname
- Chemin de l'exécutable. Absolu ou relatif ; doit être un fichier ordinaire avec permission d'exécution ou un script interprété (#!/…) chargeable par le noyau.
- argv
- Tableau d'arguments terminé par NULL. Par convention argv[0] est le nom du programme tel que l'appelant veut le voir apparaître.
- envp
- Tableau d'environnement terminé par NULL, sous forme NOM=valeur. Passer environ pour hériter, ou un tableau filtré pour nettoyer les variables sensibles.
Description
execve() remplace les segments texte, données, BSS et pile du processus appelant par ceux d'un nouveau programme, tout en conservant le PID, le PID parent, les descripteurs de fichier ouverts (sauf si O_CLOEXEC est positionné), les signaux en attente et les limites de ressources. Le nouveau programme reçoit argv comme vecteur d'arguments et envp comme environnement ; les deux tableaux doivent être terminés par NULL. En cas de succès, execve() ne retourne pas — le contrôle passe au point d'entrée du nouveau programme. En cas d'échec elle retourne -1 avec errno positionné et l'appelant poursuit. Les bits set-UID / set-GID peuvent s'appliquer sous réserve de no_new_privs, des montages nosuid et des règles de capacités.
Numéros par architecture
| Architecture | Numéro | ABI | Point d'entrée |
|---|---|---|---|
| x86 (i386) | 11 | i386 | sys_execve |
| x64 (x86_64) | 59 | 64 | sys_execve |
| ARM64 (aarch64) | 221 | — | — |
Historique noyau
Introduit dans Linux 1.0.
1.0
execve() est présent dans Linux depuis 1.0 et suit POSIX.1 dans l'ensemble, avec des comportements spécifiques Linux autour des interpréteurs #! et de la comptabilité ARG_MAX.
3.19
execveat() a été ajouté comme variante relative à un descripteur de répertoire (analogue à openat) et pour permettre d'exécuter un descripteur de fichier directement (AT_EMPTY_PATH).
5.7
La profondeur maximale de récursion d'interpréteurs #! a été durcie contre les cas pathologiques pouvant provoquer un épuisement de la pile noyau via des chaînes profondément imbriquées.
seccomp & conteneurs
Docker default profile
Autorisé
Podman default profile
Autorisé
execve() et execveat() figurent dans les profils par défaut de Docker / Podman. Le blocage de execve() est le durcissement de conteneur le plus efficace pour les charges qui ne doivent jamais lancer de binaire — par ex. un serveur web qui ne fait que lire des fichiers et écrire sur des sockets. Après le lancement des binaires nécessaires, un wrapper init peut installer un filtre seccomp refusant execve() / execveat(), éliminant toute une classe de mouvements post-exploitation (drop de shell, chargement latéral). no_new_privs et le retrait de CAP_SYS_PTRACE se combinent bien.
libseccomp
// Block execve from a process — disables ability to spawn binaries
seccomp_rule_add(ctx, SCMP_ACT_ERRNO(EPERM), SCMP_SYS(execve), 0);
seccomp_rule_add(ctx, SCMP_ACT_ERRNO(EPERM), SCMP_SYS(execveat), 0);Exemple strace
$ strace -f -e execve /bin/sh -c 'ls /tmp'
execve("/bin/sh", ["/bin/sh", "-c", "ls /tmp"], 0x7ffd8c4f3a18 /* 28 vars */) = 0
execve("/usr/bin/ls", ["ls", "/tmp"], 0x55a9b2e1d010 /* 28 vars */) = 0
+++ exited with 0 +++strace -f suit les enfants fork/clone, donc execve depuis un sous-shell est capturé. Le troisième argument (envp) est affiché 0x… /* N vars */ par défaut — passer --strings-in-hex=none -v pour le déployer. Utiliser -e trace=execve,execveat pour filtrer.
Sécurité & observabilité
execve() est la primitive post-exploitation canonique — tout drop de shell, tout chargeur de binaire, tout chemin d'élévation de privilèges y passe. Le sous-système audit émet des enregistrements execve (-a always,exit -F arch=b64 -S execve), et le tracepoint eBPF sched_process_exec capture le nom du programme, le parent et l'environnement. Certains rootkits hookent execve pour substituer /bin/ps par une version filtrée, ou pour lancer un binaire caché sur certains arguments ; comparer la sortie du tracepoint à /proc/<pid>/exe est la vérification standard. Pour la sécurité conteneur, un execve inattendu depuis un pod de charge mérite presque toujours une alerte.
Erreurs
- E2BIG
- La combinaison argv + envp + vecteur auxiliaire dépasse la limite ARG_MAX du noyau (généralement 128 KiB, ou 1/4 de RLIMIT_STACK sur les noyaux récents).
- EACCES
- Permission de recherche refusée sur un composant, ou pathname non exécutable, ou système de fichiers monté noexec.
- EFAULT
- —
- EINVAL
- —
- EIO
- —
- EISDIR
- —
- ELIBBAD
- Un interpréteur ELF (par ex. ld.so) référencé dans le binaire n'a pas pu être chargé.
- ELOOP
- Trop de niveaux de liens symboliques ou d'interpréteurs ont été traversés.
- EMFILE
- —
- ENAMETOOLONG
- —
- ENFILE
- —
- ENOENT
- —
- ENOEXEC
- Le fichier est reconnu mais n'est pas dans un format exécutable supporté (architecture incorrecte, ELF corrompu).
- ENOMEM
- —
- ENOTDIR
- —
- EPERM
- Le système de fichiers est monté nosuid et le binaire est set-UID/GID, ou no_new_privs bloque l'élévation de privilèges.
- ETXTBSY
- Le binaire est actuellement ouvert en écriture par un autre processus.