Docker Engine 29.8.0 ajoute l’option --umask et bloque un chemin d’évasion sandbox en 32 bits
Docker Engine 29.8.0, publié le 3 septembre 2026, introduit l’option --umask pour fixer le masque de permissions des processus d’un conteneur et ajoute des règles AppArmor/SELinux qui bloquent l’appel socketcall(2) 32 bits vers AF_VSOCK. Mettez à jour si vous partagez des volumes entre hôte et conteneur ou si vous durcissez vos conteneurs.
3 septembre 2026. Docker Engine 29.8.0 est publié, et deux changements méritent l’attention des équipes qui opèrent des conteneurs en production. Le premier est fonctionnel : l’option --umask, demandée depuis des années, permet enfin de fixer le masque de permissions d’un conteneur. Le second est défensif : des règles AppArmor et SELinux bloquent désormais l’appel socketcall(2) en 32 bits utilisé pour créer des sockets AF_VSOCK — un chemin d’évasion potentiel vers les machines virtuelles de l’hôte. Pourquoi c’est important : ce sont deux corrections qui touchent directement la surface de sécurité des conteneurs, pas le confort cosmétique.
—umask : le masque de permissions devient explicite
Historiquement, un conteneur héritait du umask du daemon dockerd — presque toujours 0022 — sans que l’opérateur puisse le surcharger par conteneur. Les images qui écrivaient des fichiers sensibles dans des volumes partagés produisaient alors des fichiers lisibles par tous (0644), ou avec des droits de groupe hérités de façon imprévisible.
Docker Engine 29.8.0 introduit HostConfig.Umask et le flag --umask <octal> sur docker create et docker run. La valeur s’applique au processus principal, aux execs et aux healthchecks — trois endroits où un masque incohérent causait des fuites de permissions.
L’usage est direct :
# Fichiers créés en 0600 (rw-------) au lieu de 0644 (rw-r--r--)
docker run --rm --umask 077 alpine sh -c 'umask && touch /data/secret && ls -l /data/secret' Le premier umask affiche 0077, et le fichier /data/secret sort en -rw-------. Pour un secret, une clé privée ou un jeton écrit dans un volume monté, c’est la différence entre un fichier lisible par le seul propriétaire et un fichier lisible par tout l’hôte.
Le scénario le plus fréquent est celui du volume partagé entre conteneurs. Deux services qui se partagent un volume, avec des UID différents, produisent des fichiers que l’autre ne peut ni lire ni modifier — ou, pire, que tout le monde peut lire quand l’un d’eux s’exécute avec un masque permissif. En fixant --umask explicitement, on rend le comportement déterministe et reproductible d’une machine à l’autre, ce que les opérateurs réclament depuis qu’ils déploient en orchestration.
Pourquoi —umask a mis si longtemps
La demande de --umask remonte à plus de dix ans et figure parmi les issues les plus suivies de moby/moby. Le blocage n’était pas technique mais sémantique : quel umask un conteneur doit-il utiliser par défaut, et qui — l’image, le daemon ou l’opérateur — a le dernier mot ? Un masque trop permissif crée des fichiers lisibles par tous ; un masque trop strict casse les images qui supposent 0022.
La réponse de 29.8.0 est pragmatique : --umask est optionnel, et sans lui, le comportement hérité ne change pas d’un iota. C’est la bonne manière d’introduire une option de sécurité : opt-in, explicite, sans rupture de compatibilité. Les équipes qui en ont besoin l’adoptent immédiatement ; les autres ne voient aucune différence.
La règle socketcall(2) : fermer un chemin d’évasion en 32 bits
Le second changement est plus subtil et plus défensif. Sur x86 32 bits, les appels système liés aux sockets passent tous par un multiplexeur unique, socketcall(2), au lieu des appels dédiés (socket, connect…) du 64 bits. Docker bloque maintenant ce chemin via des règles AppArmor et SELinux pour empêcher un conteneur d’utiliser socketcall(2) afin de créer des sockets AF_VSOCK.
AF_VSOCK est la famille d’adresses qui relie un invité à son hyperviseur (le canal vsock des machines virtuelles). Laisser un conteneur — surtout un conteneur privilégié ou exécutant du code non fiable — créer ce type de socket, c’est lui tendre un canal vers la couche de virtualisation de l’hôte. La règle ne supprime pas la fonctionnalité : elle ferme la route détournée en 32 bits, laissant les chemins 64 bits, eux-mêmes couverts par les politiques existantes.
C’est de la défense en profondeur classique : on ne corrige pas une vulnérabilité précise, on retire un vecteur entier dont l’exploitation nécessiterait une chaîne de préconditions.
Concrètement, le risque visé est celui du conteneur qui atteint la couche hyperviseur. Les sockets AF_VSOCK sont le canal standard par lequel un invité — VM ou conteneur — dialogue avec l’hôte : vsock est le mécanisme utilisé par virtio-vsock et les agents de machine virtuelle. Un conteneur qui parvient à en créer un contourne l’isolation réseau classique (namespaces, pare-feu) pour parler directement à l’infrastructure sous-jacente.
Le gabarit AppArmor devient configurable
Le troisième changement de sécurité de la version est moins spectaculaire mais tout aussi utile : le daemon peut désormais configurer le gabarit du profil AppArmor par défaut appliqué aux conteneurs. Jusqu’ici, durcir ce profil exigeait de le remplacer manuellement ou de maintenir des profils par conteneur — une opération fragile, souvent abandonnée en pratique.
Avec ce réglage, une équipe peut définir une politique de base une fois, la versionner avec le reste de l’infrastructure, et la voir appliquée uniformément à tous les conteneurs non privilégiés. Combiné à la règle socketcall(2), c’est un pas de plus vers un durcissement par défaut, sans bricolage post-installation.
Le reste de la version
La version 29.8.0 ne se résume pas à ces trois points. Côté journalisation, le pilote awslogs peut attacher des noms de service, des environnements et des attributs d’entité CloudWatch personnalisés aux logs.
Côté réseau, une série de correctifs Swarm réduit le trafic de gossip et stabilise la résolution de noms après une panne de nœud. Côté rootless, RootlessKit passe en v3.1.0 et introduit le pilote de ports pesto (IPv4 uniquement, avec le pilote réseau pasta) — une simplification bienvenue pour les équipes qui publient des ports en mode rootless, un point de friction récurrent. Enfin, la base technique remonte d’un cran : BuildKit 0.33.0, containerd 2.3.4, runc 1.5.1 et Go 1.26.8.
Vérifier après mise à jour
Deux contrôles suffisent pour valider une mise à niveau. Le premier vérifie le masque effectif d’un conteneur :
docker run --rm --umask 0027 alpine umask La sortie doit afficher 0027. Le second contrôle le profil AppArmor appliqué à un conteneur de test, via le champ AppArmorProfile renvoyé par docker inspect. Si les deux répondent correctement, la version est opérationnelle et le chemin socketcall(2) est couvert par les nouvelles règles. Ces deux vérifications tiennent en moins d’une minute et suffisent à écarter une régression silencieuse.
Verdict
Si vous partagez des volumes entre l’hôte et des conteneurs, ou si vos images écrivent des secrets, des clés ou des journaux dans des montages, mettez à jour et adoptez --umask sans attendre — c’est une correction d’une classe entière de bugs de permissions, gratuite à appliquer. Si vous durcissez vos conteneurs avec AppArmor ou SELinux, la règle socketcall(2) est une brique défensive de plus qui ne coûte rien en compatibilité pour la quasi-totalité des charges. Si vous restez sur une version antérieure de la série 29, la mise à niveau est de faible risque : aucun breaking change majeur, une base technique simplement rafraîchie.
Le point de vigilance reste le conteneur privilégié : les règles AppArmor et SELinux ne couvrent pas un conteneur lancé en --privileged, qui conserve par construction l’accès au noyau de l’hôte. La défense en profondeur de 29.8.0 s’applique à la masse des conteneurs non privilégiés — et c’est déjà l’essentiel du parc. Pour le reste, le risque résiduel se traite par la réduction du nombre de conteneurs privilégiés, pas par ce correctif.