Skip to content
/linux-syscalls

Systèmes de fichiers & Montages · Section 2

chroot(2)

Change le répertoire racine apparent du processus appelant et de ses enfants.

Signature

#include <unistd.h>

int chroot(const char * path);
path
Répertoire qui deviendra la nouvelle racine apparente. Doit exister et être un répertoire.

Description

chroot() change le répertoire racine apparent du processus — les chemins débutant par / sont interprétés sous path, et les résolutions absolues ne peuvent remonter au-dessus (un /../../../ final résout vers path lui-même). Les enfants héritent de la vue chrootée. L'appel requiert CAP_SYS_CHROOT dans l'espace utilisateur de l'appelant et est intentionnellement non récupérable dans un certain sens — une fois chrooté, le processus ne peut pas facilement se déchroter (la 'cassure de chroot' classique repose sur la détention d'un fd de répertoire ouvert avant chroot() et fchdir pour grimper — d'où chroot n'est PAS une frontière de sécurité en soi). Les conteneurs n'utilisent pas chroot() pour l'isolation ; ils utilisent les espaces de montage plus pivot_root() pour échanger atomiquement toute la racine. chroot() survit surtout dans les démons hérités (bind, vsftpd, sftp-server) et comme étape de chroots de construction de paquets.

Numéros par architecture

ArchitectureNuméroABIPoint d'entrée
x86 (i386)61i386sys_chroot
x64 (x86_64)161commonsys_chroot
ARM64 (aarch64)51—sys_chroot

Historique noyau

Introduit dans Linux 1.0.

  1. 1.0

    chroot() est présent dans Linux depuis 1.0 — hérité de V7 Unix. L'absence de récursion dans le modèle de sécurité date d'alors.

  2. 2.6.16

    pivot_root() a été ajouté pour que les runtimes de conteneurs échangent atomiquement tout le système de fichiers racine (typiquement combiné à CLONE_NEWNS pour rendre le changement local à un espace de montage). Matériellement plus fort que chroot() car il déplace l'ancienne racine et peut être couplé à umount() pour la rendre inaccessible.

seccomp & conteneurs

Docker default profile

Bloqué

Podman default profile

Bloqué

chroot() est BLOQUÉ par défaut dans les profils Docker et Podman, en partie parce que les charges n'en ont presque jamais besoin (les conteneurs fournissent déjà une vue racine) et en partie parce qu'un usage incorrect peut perturber le runtime. Permettre chroot() dans un conteneur est inhabituel — cela laisse la charge créer des chroots imbriqués, rarement utile et parfois base de motifs d'évasion combinés à des mauvaises configurations de capacités.

libseccomp

// chroot is NOT on the Docker default allow-list; explicitly deny for clarity
seccomp_rule_add(ctx, SCMP_ACT_ERRNO(EPERM), SCMP_SYS(chroot), 0);

Exemple strace

$ strace -e chroot sudo chroot /opt/myroot ls /
chroot("/opt/myroot")                   = 0

chroot() apparaît une fois par processus quand utilisé. Suivre sa cible avec -y sur les open() suivants révèle la vue chrootée. Combiné à -e file, on peut auditer exactement quels fichiers le processus chrooté touche — utile pour minimiser le contenu d'un chroot.

Sécurité & observabilité

chroot() est largement incompris comme frontière de sécurité ; il ne l'est pas. Un processus dans un chroot conservant : CAP_SYS_CHROOT, un fd de répertoire ouvert hors chroot, ptrace sur un processus extérieur, permission mknod pour créer /dev/sda — peut trivialement s'évader. L'évasion classique : fchdir(saved_fd) → chdir('../') × 100 → chroot('.') → /bin/sh. Pour de l'isolation réelle, utiliser espaces de montage + pivot_root + bind-mount en lecture seule, ou Landlock pour des restrictions par chemin. Le tracepoint eBPF sys_enter_chroot est rare en trafic de production ; un chroot() inattendu dans un conteneur non encore chrooté mérite alerte. Les démons set-UID qui chroot() puis abandonnent les privilèges (motif BIND) sont l'usage non-conteneur légitime.

Erreurs

EACCES
Permission de recherche refusée sur un composant.
EFAULT
—
EIO
—
ELOOP
Trop de liens symboliques.
ENAMETOOLONG
—
ENOENT
path inexistant.
ENOMEM
—
ENOTDIR
path n'est pas un répertoire.
EPERM
Appelant sans CAP_SYS_CHROOT dans son espace utilisateur.

Syscalls liés