flawopen.com/Teardowns/cve-2024-21626-runc-container-breakout-leaky-vessels
CVE-2024-21626 : comment runc a corrigé l’évasion Leaky Vessels
CVE-2024-21626 associait une fuite interne de descripteur dans runc à l’absence de vérification après chdir. Selon le chemin de lancement, le conteneur pouvait démarrer avec un répertoire de travail dans l’espace de noms de l’hôte ou atteindre des fichiers de l’hôte par un chemin lié à exec.[1], [2], [3]
runc prépare une pièce isolée pour le conteneur. Un handle interne divulgué pouvait faire pointer le répertoire de travail choisi hors de cette pièce ; la vérification finale de la limite et la fermeture des handles internes bloquent ce passage.[1], [2]
Concepts Clés et Termes
runc- Le runtime OCI qui crée et démarre les conteneurs.[1]
Descripteur de fichier interne- Handle du système d’exploitation vers un fichier ou répertoire ouvert. Un descripteur divulgué peut conserver un accès entre processus s’il reste ouvert pendant le lancement d’un enfant.[1], [3]
cwd- Répertoire de travail du processus. Sous Linux, Getwd peut renvoyer ENOENT lorsqu’il se trouve hors de la racine de l’espace de noms de montage.[1], [2]
Évasion de conteneur- Chemin permettant à un processus du conteneur d’accéder aux ressources de l’hôte situées hors de sa frontière d’isolation.[1]
Correspondances de référentiels
- Référence CWE pour la faiblesse décrite dans ce guide : CWE-403
Analyse de Cause Racine
Avant runc 1.1.12, des descripteurs internes pouvaient fuiter vers runc init. Ils restaient internes à runc init et n’étaient pas simplement hérités par le processus du conteneur. Dans les attaques 1 et 2, le répertoire de travail configuré ou choisi pouvait être résolu via un handle de l’espace de noms de montage de l’hôte ; runc ne vérifiait pas après chdir que le répertoire final restait dans la racine du conteneur. D’autres variantes exploitaient le traitement des chemins d’execve pour écraser un binaire de l’hôte. La version 1.1.12 a ajouté quatre protections : vérifier cwd avec le comportement Getwd/ENOENT de Linux, fermer les descripteurs internes juste avant execve, corriger les fuites identifiées et marquer les descripteurs non-stdio close-on-exec avant de lancer runc init.[1], [2], [3], [4]
CVE-2024-21626 : variantes d’attaque et protections de runc 1.1.12
| Variante de l’avis | Conditions et frontière requises | Correctif ou mesure temporaire pertinente |
|---|---|---|
Attaque 1 — image malveillante avec runc run | Un utilisateur privilégié doit être amené à lancer une image non fiable. Son répertoire de travail configuré peut se résoudre hors de l’espace de noms de montage du conteneur. | Le contrôle unix.Getwd() après chdir échoue si cwd se trouve hors de la racine de l’espace de noms. En attendant le correctif, n’autorisez que / comme cwd pour les images non fiables. |
Attaque 2 — processus du conteneur et runc exec | Un processus dans le conteneur doit anticiper le choix par l’administrateur d’un cwd autre que / avec runc exec --cwd, puis préparer le chemin concerné avant l’exécution. | Le même contrôle de cwd après chdir bloque l’exécution hors du conteneur. Limitez --cwd à / jusqu’à la mise à jour. |
| Attaque 3a — écrasement d’un binaire hôte au lancement d’image | Cette variante adapte l’attaque 1 et exige toujours qu’un utilisateur privilégié lance l’image malveillante ; elle franchit la frontière execve vers un binaire de l’hôte. | Fermez les descripteurs internes de runc juste avant execve, corrigez les fuites identifiées et définissez O_CLOEXEC. Mettez à jour vers runc 1.1.12 ou une version corrigée par le fournisseur. |
Attaque 3b — écrasement d’un binaire hôte via runc exec | Cette variante adapte l’attaque 2 et part d’un processus malveillant dans un conteneur actif que l’attaquant peut influencer ; un administrateur privilégié doit néanmoins effectuer une opération normale de runc exec sur ce conteneur. L’avis indique que cette voie demande moins d’interaction utilisateur que celle par image. | Les protections de fermeture avant execve et close-on-exec couvrent cette voie distincte. Les mainteneurs ne signalent pas de contournement pratique ; mettez à jour. |
Déroulement de l'Attaque Étape par Étape
Impact et conditions
L’avis documente un accès au système de fichiers et le contrôle de l’hôte dans quatre variantes. Les attaques par image exigent qu’un utilisateur privilégié lance une image non fiable. L’attaque 3b exige toujours qu’un administrateur effectue une opération normale de runc exec sur un conteneur que l’attaquant peut influencer.[1]
Code Source : Vulnérable vs Sécurisé
// Comportement pré-correctif simplifié ; extrait non littéral de runc
if err := os.Chdir(config.Cwd); err != nil {
return err
}
// Il manquait la vérification que le cwd final reste dans la racine du namespace
// Vérification de frontière de runc 1.1.12 (extrait upstream)
if wd, err := unix.Getwd(); errors.Is(err, unix.ENOENT) {
return errors.New("cwd hors de la racine du namespace de montage du conteneur")
} else if err != nil {
return fmt.Errorf("impossible de vérifier la sécurité du cwd : %w", err)
} else if !filepath.IsAbs(wd) {
return fmt.Errorf("cwd non absolu : %q", wd)
}
Liste de Contrôle de Sécurité pour l'Ingénierie
- ✓Mettez runc à jour vers la version 1.1.12 ou une version ultérieure prise en charge et vérifiez la version effective sur chaque image de nœud.[1], [4]
- ✓Traitez les images non fiables comme des demandes d’exécution de code ; limitez les personnes autorisées à les lancer via Docker, Kubernetes et les pipelines de build.[1]
- ✓Dans un runtime, vérifiez le cwd après chdir avec le contrôle de racine de namespace pris en charge par la plateforme et échouez de manière sûre en cas d’erreur.[1], [2]
- ✓Définissez O_CLOEXEC sur les descripteurs internes et fermez les descripteurs non-stdio au dernier point sûr avant exec, en tenant compte des descripteurs propres au runtime.[1], [3]
- ✓Ne considérez pas les user namespaces comme un substitut au correctif runc ; utilisez-les comme couche d’isolation supplémentaire si possible.[1]