La bombe à retardement cachée dans macOS pendant 49 jours — les dessous d’un bug kernel qui bloque totalement le réseau TCP
(photon.codes)Un bug a été découvert dans le kernel XNU de macOS : après exactement 49 jours, 17 heures, 2 minutes et 47 secondes de fonctionnement continu, le réseau TCP se retrouve complètement paralysé. La cause est un overflow d’entier 32 bits du compteur interne d’horodatage TCP du kernel, tcp_now. ping continue de répondre, mais il devient impossible d’établir de nouvelles connexions TCP, et à l’heure actuelle la seule solution est de redémarrer.
Contexte de la découverte
Photon exploitait 24/7 une flotte de serveurs Mac surveillant l’état du service iMessage. Le 30 mars 2026, au moment précis où plusieurs machines atteignaient 49,7 jours depuis leur dernier redémarrage, elles ont commencé à refuser silencieusement toute nouvelle connexion TCP. ping fonctionnait normalement, les connexions existantes restaient actives, mais toute tentative d’ouvrir un nouveau socket échouait.
Après avoir restauré le service par un redémarrage, l’équipe a sélectionné deux machines (A et B) qui devaient atteindre le même seuil critique dans les jours suivants, et a conçu une expérience en conditions réelles.
Le mécanisme technique du bug
Le compteur en cause : tcp_now
Dans le kernel XNU, tcp_now est un entier non signé 32 bits comptant en millisecondes le temps écoulé depuis le démarrage. La valeur maximale représentable sur 32 bits est de 4 294 967 295 ms, soit exactement 49 jours, 17 heures, 2 minutes et 47 secondes.
Pourquoi le compteur se « fige »
Le code de mise à jour de tcp_now contient une garde simple censée « empêcher l’horloge de reculer » :
if (tmp < current_tcp_now) {
os_atomic_cmpxchg(&tcp_now, tmp, current_tcp_now, ...);
}
Au moment de l’overflow, la nouvelle valeur calculée de current_tcp_now revient près de 0, tandis que tmp est proche de la valeur maximale. La condition tmp < current_tcp_now devient fausse pour toujours, ce qui fige tcp_now à cette valeur. L’horloge TCP du kernel s’arrête.
Pourquoi TIME_WAIT n’expire plus
Quand une connexion TCP se ferme, le kernel enregistre son instant d’expiration sous la forme tcp_now + 30 secondes. Un garbage collector parcourt périodiquement ces entrées et libère la connexion si tcp_now >= instant d’expiration. Mais si tcp_now est figé, cette condition ne devient plus jamais vraie, et les connexions en TIME_WAIT ne sont jamais récupérées.
Résultats de l’expérience
L’équipe a généré plusieurs connexions TCP éphémères par seconde pendant 5 minutes avant et après l’overflow, tout en observant le nombre de connexions TIME_WAIT.
| Période | État |
|---|---|
| Avant l’overflow | TIME_WAIT se maintient de façon stable autour de ~200 (expiration normale toutes les 30 secondes) |
| Juste après l’overflow | Les expirations s’arrêtent et TIME_WAIT commence à augmenter de façon monotone |
| 84 secondes après l’arrêt de la création de connexions | Au lieu de retomber à 0, TIME_WAIT augmente encore (2 828 → 2 837) |
| 9,5 heures après l’overflow | Machine A : 4 888, Machine B : 8 217 — aucune entrée récupérée |
Après 9,5 heures, plus de 3 000 connexions à l’état SYN_SENT s’étaient aussi accumulées, et la charge moyenne de la machine B avait grimpé jusqu’à 49,74.
Environnements affectés
Les Mac grand public sont généralement moins exposés, car les mises à jour de l’OS entraînent souvent un redémarrage avant 49 jours. Mais les environnements suivants présentent un risque élevé :
- flottes de serveurs fonctionnant longtemps sans interruption
- serveurs de build macOS pour CI/CD (Jenkins, runners self-hosted GitHub Actions)
- stations de travail Mac Pro (rendu ou compilation sur de longues durées)
- Mac en colocation administrés à distance
- fermes de build et infrastructures de test sur Mac mini
Réponse actuelle et à venir
L’équipe travaille actuellement sur un contournement permettant de corriger directement tcp_now figé sans redémarrage. En attendant, il n’existe qu’une mesure provisoire :
Planifiez un redémarrage avant 49 jours, 17 heures, 2 minutes et 47 secondes.
Bugs historiques similaires
Ce bug appartient à une longue lignée de bugs d’overflow d’entier : le crash des 49,7 jours de Windows 95/98, le problème de 2038 (Y2K38), le rollover du numéro de semaine GPS et l’écran de fin du niveau 256 de Pac-Man relèvent tous de la même famille.
Original : Photon Blog, 2026.04.07
Aucun commentaire pour le moment.