Skip to content
/linux-syscalls

Espaces de noms & Conteneurs · Section 2

unshare(2)

Détache certaines parties du contexte d'exécution du processus appelant — espaces de noms, fs, files — sans forker.

Signature

#include <sched.h>

int unshare(int flags);
flags
OU bit-à-bit de drapeaux CLONE_*. Chaque drapeau détache la ressource correspondante. CLONE_NEWUSER est spécial : demandable par des appelants non privilégiés (selon la config noyau), et une fois accordé l'appelant a CAP_SYS_ADMIN dans le nouvel espace — débloquant les autres demandes CLONE_NEW*.

Description

unshare() permet à un processus de détacher des ressources sélectionnées de son contexte parent sans passer par clone(). flags est un masque de valeurs CLONE_* : CLONE_NEWUSER crée un nouvel espace utilisateur, CLONE_NEWNET un nouvel espace réseau, CLONE_NEWNS un nouvel espace de montage, CLONE_NEWPID un nouvel espace de PID (effectif pour le *prochain* enfant), CLONE_NEWUTS / CLONE_NEWIPC / CLONE_NEWCGROUP / CLONE_NEWTIME pour les autres, et CLONE_FILES / CLONE_FS / CLONE_SYSVSEM pour les ressources non-espace-de-noms. unshare() est l'inverse de l'héritage : plutôt que « créer un enfant qui ne partage pas X », il dit « cesser de partager X avec quiconque ». C'est la primitive principale de la commande unshare(1) et de la construction de conteneurs rootless.

Numéros par architecture

ArchitectureNuméroABIPoint d'entrée
x86 (i386)310i386sys_unshare
x64 (x86_64)272commonsys_unshare
ARM64 (aarch64)97—sys_unshare

Historique noyau

Introduit dans Linux 2.6.16.

  1. 2.6.16

    unshare() a été ajouté en 2.6.16 avec la famille d'espaces de noms. Au départ il supportait seulement CLONE_FILES, CLONE_FS, CLONE_NEWNS, CLONE_SYSVSEM ; les noyaux suivants ont ajouté chaque nouvel espace en drapeau.

  2. 3.8

    CLONE_NEWUSER est arrivé (Linux 3.8), rendant les conteneurs rootless possibles. Le mécanisme de mapping UID/GID des espaces utilisateur est venu avec ; le motif canonique du conteneur non privilégié est unshare(CLONE_NEWUSER|CLONE_NEWNS|…) puis écriture de /proc/self/uid_map.

  3. 4.6

    CLONE_NEWCGROUP a été ajouté — un processus peut avoir une vue virtualisée de /proc/self/cgroup, utilisé par les hiérarchies cgroupv2 imbriquées.

seccomp & conteneurs

Docker default profile

Bloqué

Podman default profile

Bloqué

unshare() est BLOQUÉ par défaut dans Docker et Podman car l'autoriser dans un conteneur permet à la charge de créer des espaces imbriqués — fondation des exploits de conteneurs imbriqués et chemin riche en CVE. À activer explicitement seulement pour les conteneurs qui hébergent légitimement des runtimes imbriqués (Docker-in-Docker, Kubernetes-in-Kubernetes). Filtrer pour refuser CLONE_NEWUSER spécifiquement est une alternative plus serrée qui permet d'autres usages de unshare tout en bloquant le chemin d'escalade par espace utilisateur.

libseccomp

// unshare() is NOT on the Docker default allow-list. Explicitly deny.
seccomp_rule_add(ctx, SCMP_ACT_ERRNO(EPERM), SCMP_SYS(unshare), 0);

Exemple strace

$ strace -e unshare unshare -U -r /bin/whoami 2>&1 | head -3
unshare(CLONE_NEWUSER)                  = 0

unshare() dans strace affiche le masque de bits symboliquement. Le motif classique « je veux tester en root » est unshare(CLONE_NEWUSER) suivi d'une écriture dans /proc/self/uid_map — visible directement. Pour les commandes ip netns add on voit unshare(CLONE_NEWNET) puis des bind-mounts vers /run/netns/<nom>.

Sécurité & observabilité

unshare(CLONE_NEWUSER) est le point d'entrée des chaînes d'escalade par espace utilisateur non privilégié — historiquement plusieurs CVE (CVE-2018-18955, CVE-2022-0185, CVE-2022-2588) ont donné root via des constructions d'espace utilisateur. L'atténuation est sysctl kernel.unprivileged_userns_clone=0 sur les hôtes durcis ; Debian / Ubuntu l'activent souvent. Le tracepoint eBPF sys_enter_unshare avec les drapeaux décodés donne une observabilité complète ; une charge conteneur appelant unshare(CLONE_NEWUSER|…) est rare et mérite alerte. De l'intérieur, les readlinks /proc/self/ns/* exposent les numéros d'inode d'espaces actuels — comparer aux espaces attendus du conteneur détecte la dérive.

Erreurs

EINVAL
Combinaison de drapeaux invalide, ou drapeau non supporté par ce noyau.
ENOMEM
Mémoire noyau insuffisante.
ENOSPC
—
EPERM
Appelant sans CAP_SYS_ADMIN pour l'un des espaces demandés (tout sauf CLONE_NEWUSER sur les systèmes où l'userns non privilégié est activé). Sur Debian avec kernel.unprivileged_userns_clone=0, même CLONE_NEWUSER échoue en EPERM pour non-root.
EUSERS
La profondeur d'espaces utilisateur imbriqués dépasserait MAX_USER_NAMESPACE_LEVEL (32).

Drapeaux

CLONE_FILES
0x00000400
Détache la table des descripteurs. Après unshare(CLONE_FILES), ouvrir/fermer un fd ici n'affecte plus les frères qui partageaient la table (par ex. via clone(CLONE_FILES)).
CLONE_FS
0x00000200
—
CLONE_NEWCGROUP
0x02000000
Nouvel espace cgroup. La vue /proc/self/cgroup du processus est rebasée — utile pour la conteneurisation imbriquée.
CLONE_NEWIPC
0x08000000
—
CLONE_NEWNET
0x40000000
Nouvel espace réseau. État réseau vide (pas d'interface sauf lo). Utilisé par les runtimes de conteneurs et ip netns.
CLONE_NEWNS
0x00020000
Nouvel espace de montage. Les mount() / umount() suivants sont locaux à cet espace. Base des racines MS_PRIVATE et des montages rootless.
CLONE_NEWPID
0x20000000
Nouvel espace PID. Le prochain enfant créé via fork()/clone() devient PID 1 dans le nouvel espace ; le processus appelant reste dans l'ancien.
CLONE_NEWTIME
0x00000080
—
CLONE_NEWUSER
0x10000000
Nouvel espace utilisateur. Disponible aux appelants non privilégiés et fondation des conteneurs rootless. Dans le nouvel userns, l'appelant peut mapper une paire UID/GID et obtenir CAP_SYS_ADMIN, ce qui débloque les autres créations d'espaces.
CLONE_NEWUTS
0x04000000
—
CLONE_SYSVSEM
0x00040000
—

Syscalls liés