Processus & Threads · Section 2
clone(2)
Crée un nouveau processus qui peut partager sélectivement mémoire, descripteurs, espaces de noms et autres ressources avec son parent.
Signature
#include <sched.h>
long clone(int (*)(void *) fn, void * stack, int flags, void * arg, pid_t * parent_tid, void * tls, pid_t * child_tid);- fn
- Fonction d'entrée exécutée dans l'enfant (wrapper glibc). L'appel système brut ne prend pas de pointeur de fonction.
- stack
- Pointeur vers l'octet le plus haut de la pile enfant. L'enfant s'exécute sur cette pile ; pour les processus (sans CLONE_VM), passer NULL.
- flags
- Masque de bits CLONE_* OU avec le signal de terminaison envoyé au parent (généralement SIGCHLD).
- arg
- Argument transmis à fn dans l'enfant (wrapper glibc uniquement).
- parent_tid
- Si CLONE_PARENT_SETTID, le noyau écrit ici le TID enfant, visible par le parent.
- tls
- Descripteur de stockage local au thread utilisé avec CLONE_SETTLS ; spécifique à l'architecture.
- child_tid
- Si CLONE_CHILD_SETTID, écrit dans l'espace d'adressage enfant ; si CLONE_CHILD_CLEARTID, effacé et signalé via futex à la sortie (réveil de pthread_join).
Description
clone() est la primitive Linux derrière fork(), pthread_create() et tout runtime de conteneur. Contrairement à fork() POSIX, la nouvelle tâche peut partager sélectivement l'espace d'adressage du parent (CLONE_VM), la table des descripteurs (CLONE_FILES), le contexte du système de fichiers (CLONE_FS), les gestionnaires de signaux (CLONE_SIGHAND) et les espaces de noms (CLONE_NEWPID, CLONE_NEWNET, CLONE_NEWUSER…). Avec CLONE_THREAD plus CLONE_VM|CLONE_SIGHAND elle produit un thread ; sans ces drapeaux, un processus. clone() renvoie le TID de l'enfant au parent et 0 dans l'enfant, ou -1 avec errno. Le wrapper glibc prend un pointeur de fonction fn comme point d'entrée enfant ; l'appel système brut en assembleur a une structure différente, détaillée à la rubrique « C library/kernel differences » du man.
Numéros par architecture
| Architecture | Numéro | ABI | Point d'entrée |
|---|---|---|---|
| x86 (i386) | 120 | i386 | sys_clone |
| x64 (x86_64) | 56 | common | sys_clone |
| ARM64 (aarch64) | 220 | — | sys_clone |
Historique noyau
Introduit dans Linux 2.0.
2.0
clone() a été introduit en 2.0 comme généralisation Linux de fork(), permettant les threads avec espaces d'adressage partagés — la brique sur laquelle NPTL a été bâti.
2.4.20
CLONE_NEWNS a introduit les espaces de montage, première des primitives d'espaces de noms Linux étendues plus tard en la pleine boîte à outils des conteneurs.
2.6.24
CLONE_NEWPID et CLONE_NEWUSER ont complété l'ensemble des espaces de noms nécessaires aux conteneurs complets ; les espaces utilisateur ont rendu possibles les conteneurs rootless.
5.3
clone3() a été ajouté avec une struct clone_args passée par référence, étendant flags au-delà de la limite des 32 bits de registre et permettant d'ajouter des champs futurs sans nouveaux appels système.
seccomp & conteneurs
Docker default profile
Autorisé
Podman default profile
Autorisé
clone() figure dans les profils par défaut Docker / Podman, mais les drapeaux de création d'espaces de noms (CLONE_NEWUSER, CLONE_NEWNET, CLONE_NEWPID, CLONE_NEWNS…) sont filtrés par les profils via filtrage d'arguments. Les autoriser dans un conteneur permet l'imbrication de conteneurs — et permet à un conteneur compromis de construire un nouvel espace utilisateur en PID 1 puis d'y devenir root. Pour des charges qui n'ont pas à lancer de conteneur, refuser explicitement le jeu de drapeaux de création d'espace de noms.
libseccomp
// Allow clone but deny namespace-creation flags (defence-in-depth for containers)
seccomp_rule_add(ctx, SCMP_ACT_ERRNO(EPERM), SCMP_SYS(clone),
1, SCMP_A0(SCMP_CMP_MASKED_EQ,
CLONE_NEWUSER|CLONE_NEWNET|CLONE_NEWPID|CLONE_NEWNS, 0));Exemple strace
$ strace -f -e clone /bin/sh -c 'true'
clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7fb2a1c7da10) = 14982
[pid 14982] +++ exited with 0 +++
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=14982, si_uid=1000, si_status=0, …} ---strace -f suit automatiquement les enfants clone() ; la sortie décode le masque de bits flags. pthread_create apparaît comme clone(child_stack=…, flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID, …) — une empreinte utile pour distinguer création de thread vs de processus.
Sécurité & observabilité
clone() avec CLONE_NEWUSER est la base des primitives d'élévation par espace utilisateur — un processus qui obtient CLONE_NEWUSER devient root dans le nouvel espace et, sur des systèmes mal configurés, peut s'en servir pour s'évader. Le tracepoint eBPF sys_enter_clone avec arg0 (flags) est le point d'observation ; alerter sur le masque de création d'espace de noms. Les détections runtime de conteneurs (Falco, Tracee) s'y appuient. Certains rootkits utilisent aussi clone() pour forker des processus cachés partageant la table de fd parent (pas de nouveau /proc/<pid>/exe). Côté hôte, /proc/sys/kernel/unprivileged_userns_clone = 0 interdit la création d'espace utilisateur non privilégié sur les distributions Debian qui livrent ce levier.
Erreurs
- EAGAIN
- RLIMIT_NPROC atteint ou épuisement temporaire des ressources noyau.
- EINVAL
- Combinaison de drapeaux invalide (ex. CLONE_THREAD sans CLONE_VM ni CLONE_SIGHAND).
- ENOMEM
- Mémoire noyau insuffisante pour allouer les structures de tâche.
- ENOSPC
- —
- EPERM
- CLONE_NEWUSER demandé sans privilège (sauf si les espaces utilisateur sont activés pour les appelants non privilégiés), ou CLONE_NEW* sans CAP_SYS_ADMIN dans l'espace utilisateur parent.
- EUSERS
- —
Drapeaux
- CLONE_VM
- 0x00000100
- Partage l'espace d'adressage avec le parent — c'est ce qui fait de la nouvelle tâche un thread.
- CLONE_FS
- 0x00000200
- —
- CLONE_FILES
- 0x00000400
- Partage la table des descripteurs. Fermer un fd dans une tâche le ferme partout.
- CLONE_SIGHAND
- 0x00000800
- —
- CLONE_PIDFD
- 0x00001000
- Alloue un pidfd référant à l'enfant et l'écrit dans parent_tid (alternative moderne au signalement par PID).
- CLONE_PTRACE
- 0x00002000
- —
- CLONE_VFORK
- 0x00004000
- —
- CLONE_PARENT
- 0x00008000
- —
- CLONE_THREAD
- 0x00010000
- Place la nouvelle tâche dans le même groupe de threads (même TGID/PID) ; requiert CLONE_VM et CLONE_SIGHAND.
- CLONE_NEWNS
- 0x00020000
- Crée un nouvel espace de montage.
- CLONE_SYSVSEM
- 0x00040000
- —
- CLONE_SETTLS
- 0x00080000
- —
- CLONE_PARENT_SETTID
- 0x00100000
- —
- CLONE_CHILD_CLEARTID
- 0x00200000
- —
- CLONE_CHILD_SETTID
- 0x01000000
- —
- CLONE_NEWCGROUP
- 0x02000000
- —
- CLONE_NEWUTS
- 0x04000000
- —
- CLONE_NEWIPC
- 0x08000000
- —
- CLONE_NEWUSER
- 0x10000000
- Crée un nouvel espace utilisateur — base des conteneurs rootless.
- CLONE_NEWPID
- 0x20000000
- Crée un nouvel espace de PID ; l'enfant y devient PID 1.
- CLONE_NEWNET
- 0x40000000
- Crée un nouvel espace réseau avec ses propres interfaces et table de routage.
- CLONE_IO
- 0x80000000
- —