Espaces de noms & Conteneurs · Section 2
setns(2)
Place le thread appelant dans un espace de noms existant identifié par un descripteur de fichier.
Signature
#include <sched.h>
int setns(int fd, int nstype);- fd
- Descripteur référant un espace de noms. Depuis /proc/<pid>/ns/<type>, ou un pidfd (depuis 5.8).
- nstype
- 0 pour accepter tout type, ou l'un de CLONE_NEWNS / CLONE_NEWUSER / CLONE_NEWPID / CLONE_NEWNET / CLONE_NEWUTS / CLONE_NEWIPC / CLONE_NEWCGROUP / CLONE_NEWTIME pour exiger ce type précis. Cette dernière forme est plus sûre.
Description
setns() réassocie le thread appelant à l'espace de noms référencé par fd. fd s'obtient typiquement en open()ant l'un des fichiers /proc/<pid>/ns/* (mnt, pid, net, user, ipc, uts, cgroup, time) ou via pidfd_open() + la nouvelle forme setns(pidfd, CLONE_NEW*) (Linux 5.8+). nstype vaut soit 0 (le noyau déduit du type de fd), soit l'une des constantes CLONE_NEW* (sert de vérification — l'appel échoue si fd ne correspond pas). L'appelant doit avoir CAP_SYS_ADMIN dans l'espace utilisateur de l'espace cible (CAP_SYS_CHROOT pour les espaces de montage) ; les transitions d'espace utilisateur suivent des règles plus strictes (le nouvel userns doit être descendant du courant, ou l'appelant détenir un privilège dans le parent). setns() est le syscall derrière nsenter(1) et derrière toute implémentation de 'docker exec'.
Numéros par architecture
| Architecture | Numéro | ABI | Point d'entrée |
|---|---|---|---|
| x86 (i386) | 346 | i386 | sys_setns |
| x64 (x86_64) | 308 | common | sys_setns |
| ARM64 (aarch64) | 268 | — | sys_setns |
Historique noyau
Introduit dans Linux 3.0.
3.0
setns() a été introduit en 3.0 avec l'outillage espaces utilisateur/montage/PID qui a transformé les travaux noyau antérieurs en boîte à outils cohérente utilisable depuis l'espace utilisateur (nsenter, ip netns, runtimes conteneurs).
5.8
setns() a été étendu pour accepter un pidfd (depuis pidfd_open() ou clone(CLONE_PIDFD)) et un masque CLONE_NEW*, pour qu'un appelant entre atomiquement dans plusieurs espaces d'un processus cible sans ouvrir individuellement les /proc/<pid>/ns/*. Indispensable aux motifs sans course « entrer dans chaque espace de ce processus » utilisés par l'outillage moderne.
seccomp & conteneurs
Docker default profile
Bloqué
Podman default profile
Bloqué
setns() est BLOQUÉ par défaut dans Docker et Podman, à raison : l'autoriser laisse une charge sauter dans des espaces qu'elle ne devrait pas voir, y compris les espaces hôtes accessibles (par ex. via un bind-mount de /proc mal configuré). À activer seulement pour les charges de gestion de conteneurs (le moteur docker, kubelet) — jamais pour des charges applicatives.
libseccomp
// setns() is NOT on the Docker default allow-list.
seccomp_rule_add(ctx, SCMP_ACT_ERRNO(EPERM), SCMP_SYS(setns), 0);Exemple strace
$ strace -e setns nsenter -t 1 -m /bin/ls /proc 2>&1 | head -3
setns(3, CLONE_NEWNS) = 0setns() avec un fd /proc/<pid>/ns/<type> ouvert juste avant est le motif de trace canonique. -y résout le fd en chemin d'espace, rendant la trace auto-explicative. Le code de nsenter est lisible en parallèle de la sortie strace pour comprendre la séquence setns complète.
Sécurité & observabilité
setns() vers /proc/1/ns/mnt est la primitive canonique d'évasion de conteneur — si une charge peut atteindre un fd vers l'espace de montage PID-1 de l'hôte, setns() la place dans cet espace, où elle peut voir et modifier tout fichier de l'hôte. La plupart des chaînes d'évasion y passent. Atténuations : ne pas bind-mounter /proc dans les conteneurs, abandonner CAP_SYS_ADMIN, refuser setns() dans seccomp (par défaut). Le tracepoint eBPF sys_enter_setns est un signal à haute précision — tout appel depuis un PID conteneur non-init mérite alerte. De l'intérieur, comparer /proc/self/ns/<type> aux inodes attendus de l'espace conteneur détecte l'évasion a posteriori.
Erreurs
- EBADF
- fd n'est pas valide ou ne désigne pas un espace de noms.
- EINVAL
- nstype ne correspond pas au type réel du fd, ou type non supporté par le noyau.
- ENOMEM
- Mémoire noyau insuffisante.
- EPERM
- Appelant sans CAP_SYS_ADMIN dans l'userns cible, ou transition userns violant la règle parent-descendant.