20 Punkte von darjeeling 22 일 전 | 9 Kommentare | Auf WhatsApp teilen

Im XNU-Kernel von macOS wurde ein Bug entdeckt, bei dem das TCP-Networking nach genau 49 Tagen, 17 Stunden, 2 Minuten und 47 Sekunden ununterbrochenem Betrieb vollständig ausfällt. Ursache ist ein 32-Bit-Integer-Overflow des internen TCP-Timestamp-Zählers (tcp_now) im Kernel. ping antwortet weiter, aber neue TCP-Verbindungen lassen sich überhaupt nicht mehr aufbauen; derzeit ist ein Neustart die einzige Lösung.


Wie der Fehler entdeckt wurde

Photon betreibt eine Mac-Server-Flotte rund um die Uhr zur Überwachung des iMessage-Service-Status. Am 30. März 2026, exakt 49,7 Tage nach dem letzten Neustart, begannen mehrere Maschinen stillschweigend, neue TCP-Verbindungen abzulehnen. ping funktionierte normal, bestehende Verbindungen blieben erhalten, aber jeder Versuch, neue Sockets zu öffnen, schlug fehl.

Nach einem Neustart zur Wiederherstellung des Dienstes wählte das Team zwei Maschinen (A, B) aus, die innerhalb weniger Tage denselben kritischen Punkt erreichen würden, und entwarf ein Live-Experiment.


Technischer Mechanismus des Bugs

Der problematische Zähler tcp_now

tcp_now im XNU-Kernel ist ein 32-Bit-Unsigned-Integer, der die seit dem Boot verstrichene Zeit in Millisekunden zählt. Der maximale darstellbare 32-Bit-Wert beträgt 4.294.967.295 ms — das entspricht genau 49 Tagen, 17 Stunden, 2 Minuten und 47 Sekunden.

Warum der Zähler "einfriert"

Im Update-Code für tcp_now gibt es einen einfachen Guard, der verhindern soll, dass die Uhr rückwärts läuft:

if (tmp < current_tcp_now) {  
    os_atomic_cmpxchg(&tcp_now, tmp, current_tcp_now, ...);  
}  

Im Moment des Overflows wrappt der neu berechnete Wert current_tcp_now zurück in die Nähe von 0, während tmp noch nahe am Maximalwert liegt. Dadurch wird die Bedingung tmp < current_tcp_now für immer false, und tcp_now bleibt auf diesem Wert stehen. Die TCP-Uhr des Kernels stoppt.

Warum TIME_WAIT nicht abläuft

Wenn eine TCP-Verbindung geschlossen wird, speichert der Kernel den Ablaufzeitpunkt als tcp_now + 30 Sekunden. Ein Garbage Collector scannt periodisch und gibt die Verbindung frei, wenn tcp_now >= Ablaufzeitpunkt gilt. Wenn tcp_now jedoch eingefroren ist, wird diese Bedingung niemals wahr, sodass TIME_WAIT-Verbindungen nie wieder eingesammelt werden.


Versuchsergebnisse

Das Team erzeugte jeweils 5 Minuten vor und nach dem Overflow pro Sekunde mehrere kurzlebige TCP-Verbindungen und beobachtete die Anzahl der TIME_WAIT-Zustände.

Bereich Zustand
Vor dem Overflow TIME_WAIT blieb stabil bei ~200 (normales Ablaufen alle 30 Sekunden)
Direkt nach dem Overflow Das Ablaufen stoppt, TIME_WAIT beginnt monoton anzusteigen
84 Sekunden nach Stopp der Verbindungserzeugung TIME_WAIT, das 0 sein sollte, steigt stattdessen an (2.828 → 2.837)
9,5 Stunden nach dem Overflow Machine A: 4.888, Machine B: 8.217 — kein einziger Eintrag wurde eingesammelt

Nach 9,5 Stunden hatten sich zudem mehr als 3.000 Verbindungen im Status SYN_SENT angesammelt, und der Load Average von Machine B war auf 49,74 gestiegen.


Betroffene Umgebungen

Normale Consumer-Macs sind meist weniger betroffen, weil sie durch OS-Updates oft schon vor 49 Tagen neu gestartet werden. Hochriskant sind jedoch folgende Umgebungen:

  • Server-Flotten mit langer Uptime ohne Unterbrechung
  • macOS-CI/CD-Build-Server (Jenkins, GitHub Actions Self-Hosted Runner)
  • Mac Pro-Workstations (lang laufende Rendering- oder Compile-Jobs)
  • Remote-verwaltete Colocation-Macs
  • Mac mini-Build-Farmen und Test-Infrastrukturen

Aktuelle und künftige Gegenmaßnahmen

Das Team entwickelt derzeit einen Workaround, der das eingefrorene tcp_now ohne Neustart direkt korrigiert. Bis dahin gibt es nur eine Übergangsmaßnahme:

Plant einen Neustart vor 49 Tagen, 17 Stunden, 2 Minuten und 47 Sekunden ein.


Ähnliche historische Bugs

Dieser Bug gehört zu einer langen Reihe von Integer-Overflow-Fehlern: der 49,7-Tage-Crash von Windows 95/98, das Jahr-2038-Problem (Y2K38), der GPS-Week-Number-Rollover und der Pac-Man-256-Level-Killscreen gehören alle in dieselbe Familie.


Original: Photon Blog, 2026.04.07

9 Kommentare

 
brilliant08 22 일 전

Heutzutage hält macOS also sogar die 49-Tage-Zeremonie ab.

 
bungker 17 일 전

Hahahahaha

 
roxie 21 일 전

zzzzz

 
devil1032 21 일 전

Wenn es um Zeitprobleme geht, muss ich an Y2K denken.. 🤖..

 
savvykang 21 일 전

Menschen wiederholen dieselben Fehler.

 
shincad 20 일 전

Dann muss man also tatsächlich vor Ablauf von 49 Tagen neu starten.

Eigentlich darf man Zeitwerte nie mit absolutem < vergleichen …

if ((int32_t)(tmp - current_tcp_now) < 0) {
os_atomic_cmpxchg(&tcp_now, tmp, current_tcp_now, ...);
}
So müsste man die Differenz zwischen den beiden Werten prüfen … Aber Menschen machen eben immer wieder dieselben Fehler.

 
icosahedron 21 일 전

Wenn man so etwas sieht, könnte es 2038 vielleicht wirklich chaotisch werden.

 
princox 21 일 전

Wow, das ist wirklich völlig unglaublich....

 
jic5760 21 일 전

Wie hatten AWS- oder GitHub-Mac-Instances bisher eigentlich kein Problem damit ...?