flawopen.com/Teardowns/cve-2024-26642-linux-nftables-anonymous-set-timeout
CVE-2024-26642 : ensemble anonyme avec drapeau de timeout dans nf_tables de Linux
CVE-2024-26642 (CVSS 7.8 selon le NIST) : nf_tables_newset() acceptait des ensembles anonymes portant aussi le drapeau de timeout, une combinaison qu'aucun outil de l'espace utilisateur ne crée, ce qui exposait des ensembles liés à une règle à l'expiration d'éléments et au ramasse-miettes. Linux 6.8 la refuse avec -EOPNOTSUPP.
Un vestiaire a deux systèmes. Les crochets numérotés appartiennent à un seul invité pour une soirée et sont libérés dès qu'il part. Les tickets horodatés sont ramassés chaque heure par un employé qui retire tout ce qui a expiré. Le formulaire permet de cocher les deux cases pour le même manteau : le crochet est alors libéré au départ de l'invité et aussi lors de la tournée de l'employé. Deux personnes pensent gérer le même crochet et aucune n'a été formée au planning de l'autre. Le correctif est simple : le formulaire refuse désormais cette paire de cases.
Concepts Clés et Termes
nf_tables set- Structure du noyau contenant des adresses, ports ou autres clés que les règles nftables comparent ; créée par un message netlink
NFT_MSG_NEWSETet traitée parnf_tables_newset(). Ensemble anonyme (NFT_SET_ANONYMOUS)- Ensemble sans nom, comme
{ 22, 80 }écrit directement dans une règle. Il est lié à cette seule règle et détruit avec elle dans la même transaction. NFT_SET_TIMEOUT- Drapeau qui donne aux éléments de l'ensemble une date d'expiration. Les éléments expirés sont retirés par le ramasse-miettes de l'ensemble.
NFT_SET_EVAL- Drapeau des ensembles mis à jour depuis le chemin des paquets, utilisé par les instructions
meterhistoriques. Le correctif garde anonyme + timeout + eval autorisé pour elles. CAP_NET_ADMIN dans un user namespace- nf_tables accepte la configuration de tout processus détenant CAP_NET_ADMIN dans son namespace réseau, ce qu'un utilisateur non privilégié obtient en créant un user namespace là où la distribution le permet.
Analyse de Cause Racine
nf_tables_newset() dans net/netfilter/nf_tables_api.c ne vérifiait dans les drapeaux de l'ensemble que les bits inconnus et les conflits MAP+OBJECT et EVAL+OBJECT. Elle acceptait NFT_SET_ANONYMOUS | NFT_SET_TIMEOUT : un ensemble dont la durée de vie est liée à une seule règle et à une transaction pouvait donc aussi avoir des éléments qui expirent et sont récupérés par le ramasse-miettes. L'espace utilisateur ne produit jamais cette combinaison et le code de gestion de durée de vie n'a pas été conçu pour elle. Le correctif amont la refuse avec -EOPNOTSUPP, sauf si NFT_SET_EVAL est aussi présent. Le dossier public ne détaille pas l'erreur mémoire qui en découle ; le NIST la note 7.8 (confidentialité, intégrité et disponibilité élevées), la CNA du noyau 5.5 (disponibilité seule).
Déroulement de l'Attaque Étape par Étape
Obtenir CAP_NET_ADMIN
Un utilisateur local crée un user namespace et un namespace réseau (là où les user namespaces non privilégiés sont activés) et détient ainsi CAP_NET_ADMIN sur l'état nf_tables de ce namespace.
Demander l'ensemble invalide
Dans un lot netlink, le processus envoie NFT_MSG_NEWSET avec NFTA_SET_FLAGS = NFT_SET_ANONYMOUS | NFT_SET_TIMEOUT et lie l'ensemble à une nouvelle règle via une expression de lookup.
Le noyau l'accepte
nf_tables_newset() ne trouve aucune paire de drapeaux interdite et crée un ensemble anonyme lié à la règle, dont les éléments portent une date d'expiration.
Chemins de durée de vie non testés
Valider, annuler ou supprimer la règle déclenche alors à la fois la destruction de l'ensemble et le ramassage des éléments, dans des chemins que le code transactionnel de nf_tables ne gère pas de façon sûre.
Code Source : Vulnérable vs Sécurisé
/* net/netfilter/nf_tables_api.c: nf_tables_newset(), before the fix */
if (nla[NFTA_SET_FLAGS] != NULL) {
flags = ntohl(nla_get_be32(nla[NFTA_SET_FLAGS]));
if (flags & ~(NFT_SET_ANONYMOUS | NFT_SET_CONSTANT |
NFT_SET_INTERVAL | NFT_SET_TIMEOUT |
NFT_SET_MAP | NFT_SET_EVAL |
NFT_SET_OBJECT | NFT_SET_CONCAT | NFT_SET_EXPR))
return -EOPNOTSUPP;
/* Only one of these operations is supported */
if ((flags & (NFT_SET_MAP | NFT_SET_OBJECT)) ==
(NFT_SET_MAP | NFT_SET_OBJECT))
return -EOPNOTSUPP;
if ((flags & (NFT_SET_EVAL | NFT_SET_OBJECT)) ==
(NFT_SET_EVAL | NFT_SET_OBJECT))
return -EOPNOTSUPP;
/* BUG: NFT_SET_ANONYMOUS | NFT_SET_TIMEOUT is accepted. A rule-bound
* anonymous set now also gets per-element expiry and garbage
* collection, a combination nft never creates and the set
* lifetime code was not written for. */
}
/* net/netfilter/nf_tables_api.c: nf_tables_newset(), commit 16603605b667 */
if (nla[NFTA_SET_FLAGS] != NULL) {
flags = ntohl(nla_get_be32(nla[NFTA_SET_FLAGS]));
if (flags & ~(NFT_SET_ANONYMOUS | NFT_SET_CONSTANT |
NFT_SET_INTERVAL | NFT_SET_TIMEOUT |
NFT_SET_MAP | NFT_SET_EVAL |
NFT_SET_OBJECT | NFT_SET_CONCAT | NFT_SET_EXPR))
return -EOPNOTSUPP;
/* Only one of these operations is supported */
if ((flags & (NFT_SET_MAP | NFT_SET_OBJECT)) ==
(NFT_SET_MAP | NFT_SET_OBJECT))
return -EOPNOTSUPP;
if ((flags & (NFT_SET_EVAL | NFT_SET_OBJECT)) ==
(NFT_SET_EVAL | NFT_SET_OBJECT))
return -EOPNOTSUPP;
/* FIX: anonymous sets are never used with timeouts from userspace,
* so reject the combination before the set exists. NFT_SET_EVAL
* stays allowed so legacy meters keep working. */
if ((flags & (NFT_SET_ANONYMOUS | NFT_SET_TIMEOUT | NFT_SET_EVAL)) ==
(NFT_SET_ANONYMOUS | NFT_SET_TIMEOUT))
return -EOPNOTSUPP;
}
Liste de Contrôle de Sécurité pour l'Ingénierie
- ✓Exécutez un noyau contenant le commit 16603605b667 (Linux 6.8, ou un noyau stable ou de distribution dont le changelog cite
CVE-2024-26642). - ✓Là où les charges n'en ont pas besoin, désactivez les user namespaces non privilégiés (
kernel.sous Debian et Ubuntu,unprivileged_userns_clone=0user., ou la restriction userns d'AppArmor sous Ubuntu) pour que les utilisateurs locaux n'atteignent pas nf_tables.max_user_namespaces=0 - ✓Sur les hôtes qui n'utilisent pas nftables, empêchez le chargement du module
nf_tables. - ✓Dans le code noyau et les API, exprimez les combinaisons de drapeaux acceptées sous forme de liste blanche explicite et refusez tout ce qu'aucun client pris en charge ne produit, au lieu de refuser seulement les paires connues comme mauvaises.
- ✓Fuzzez les interfaces netlink avec des descriptions syzkaller couvrant chaque bit de drapeau, pour que les combinaisons inhabituelles atteignent d'abord en test le code de durée de vie des objets.