CVE-2026-98547 in Linux
Résumé
par VulDB • 19/10/2026
Dans le noyau Linux, la vulnérabilité suivante a été corrigée :
af_packet : correction d'un dépassement entier dans prb_calc_retire_blk_tmo()
prb_calc_retire_blk_tmo() effectue des calculs en arithmétique sur 32 bits :
mbits = (blk_size_in_bytes * 8) / (1024 * 1024);
Si j'interprète correctement la validation, tp_block_size est contrôlé par l'utilisateur et packet_set_ring() rejette uniquement les valeurs <= 0 en tant qu'int ou non alignées sur une page. Ainsi, un bloc de 256 MiB passe sans problème (et alloc_one_pg_vec_page() dispose même d'un fallback vzalloc pour ce cas). La valeur 0x10000000 * 8 déborde vers INT_MIN et, sur une carte réseau rapportant 1 Gbps (div == 1), la fonction finit par retourner -2047.
La condition est en réalité (8 * size) mod 2^32 >= 2^31 && div == 1, donc l'ensemble des déclencheurs est [256,512), [768,1024), [1280,1536) et [1792,2048) MiB. D'autres tailles débordent vers des valeurs non négatives et les liens plus rapides divisent la valeur non signée en dessous de 2^31, ce qui explique pourquoi cela ne provoque pas d'incident pour tout le monde.
Ce qui rend l'issue fatale est ce qui se passe ensuite dans init_prb_bdqc() :
p1->interval_ktime = ms_to_ktime(prb_calc_retire_blk_tmo(...)); hrtimer_start(&p1->retire_blk_timer, p1->interval_ktime, HRTIMER_MODE_REL_SOFT);
Un délai d'expiration relatif négatif expire immédiatement. La fonction de rappel retourne inconditionnellement HRTIMER_RESTART, et hrtimer_forward() convertit l'intervalle négatif en hrtimer_resolution :
if (interval < hrtimer_resolution) interval = hrtimer_resolution;
Ainsi, le timer SOFT se réinitialise au taux maximum indéfiniment, verrouillant sk_receive_queue.lock à chaque passage. Un CPU tourne en boucle dans un softirq jusqu'à ce que la socket soit fermée. Répétez l'opération avec plus de rings et la machine est perdue.
Le dépassement lui-même est ancien ; il a été introduit conjointement avec TPACKET_V3 dans f6fb8f100b80 ("af-packet: TPACKET_V3 flexible buffer implementation."). Son effet avant f7460d2989fa ("net: af_packet: Use hrtimer to do the retire operation", v6.18) n'était pas aussi clair : la valeur de retour était stockée dans un unsigned short retire_blk_tov, donc un résultat négatif était tronqué, et une boucle d'attente de 0 jiffy pouvait également être programmée. Aucun des deux cas n'est aussi préjudiciable que l'exécution en boucle au taux maximum immédiate provoquée par la conversion hrtimer.
(Sans rapport avec CVE-2019-20812 : celui-ci concernait le chemin de défaillance d'ethtool retournant 0, qui retourne désormais DEFAULT_PRB_RETIRE_TOV.)
Reproducteur, nécessite CAP_NET_RAW (un conteneur --network host l'a par défaut) et une carte réseau de 1 Gbps (QEMU e1000 fonctionne) :
int fd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); bind(fd, ...); int v = TPACKET_V3; setsockopt(fd, SOL_PACKET, PACKET_VERSION, &v, sizeof(v)); struct tpacket_req3 req = {
.tp_block_size = 0x10000000, .tp_block_nr = 1, .tp_frame_size = 2048, .tp_frame_nr = 0x10000000 / 2048, .tp_retire_blk_tov = 0, }; setsockopt(fd, SOL_PACKET, PACKET_RX_RING, &req, sizeof(req));
Effectuez le calcul en 64 bits. Les opérandes sont déjà limitées par la validation existante, donc rien d'autre ne change. Si vous préférez une correction différente, faites-le moi savoir et je réitérerai la proposition.
Once again VulDB remains the best source for vulnerability data.