macOS में छिपा 49-दिन का टाइम बम — TCP networking को पूरी तरह रोक देने वाले kernel bug की पूरी कहानी
(photon.codes)macOS XNU kernel में ठीक 49 दिन 17 घंटे 2 मिनट 47 सेकंड लगातार चलने के बाद TCP networking पूरी तरह ठप कर देने वाला bug मिला है। इसकी वजह kernel के अंदर TCP timestamp counter (tcp_now) का 32-bit integer overflow है। ping जवाब देता रहता है, लेकिन नए TCP connection बिल्कुल नहीं बन पाते, और फिलहाल एकमात्र समाधान reboot है.
खोज कैसे हुई
Photon iMessage service की स्थिति मॉनिटर करने वाले Mac server fleet को 24/7 चला रहा था। 30 मार्च 2026 को, आखिरी reboot के ठीक 49.7 दिन बाद, कई machines ने चुपचाप नए TCP connection reject करने शुरू कर दिए। ping सामान्य था, मौजूदा connection भी बने रहे, लेकिन नया socket खोलने की हर कोशिश fail हो रही थी।
service बहाल करने के लिए reboot करने के बाद, टीम ने ऐसी दो machines (A, B) चुनीं जो कुछ ही दिनों में उसी critical point पर पहुंचने वाली थीं, और live experiment डिजाइन किया।
bug का तकनीकी सिद्धांत
समस्या वाला counter tcp_now
XNU kernel का tcp_now boot के बाद बीता समय millisecond इकाई में गिनने वाला 32-bit unsigned integer है। 32-bit में व्यक्त की जा सकने वाली अधिकतम value 4,294,967,295ms है — यानी ठीक 49 दिन 17 घंटे 2 मिनट 47 सेकंड।
counter "freeze" क्यों हो जाता है?
tcp_now update code में एक साधारण guard है जो यह सुनिश्चित करता है कि "clock पीछे न जाए":
if (tmp < current_tcp_now) {
os_atomic_cmpxchg(&tcp_now, tmp, current_tcp_now, ...);
}
overflow के क्षण में, नया calculate किया गया current_tcp_now फिर से 0 के आसपास wrap हो जाता है, जबकि पुराना tmp maximum value के करीब होता है। condition tmp < current_tcp_now हमेशा के लिए false हो जाती है, और tcp_now उसी value पर अटक जाता है। यानी kernel की TCP clock रुक जाती है।
TIME_WAIT expire क्यों नहीं होता
जब TCP connection बंद होता है, kernel expiry time को tcp_now + 30 सेकंड के रूप में दर्ज करता है। एक periodic garbage collector scan करके tcp_now >= expiry time होने पर connection हटा देता है। लेकिन जब tcp_now freeze हो जाता है, तो यह condition कभी true ही नहीं होती, इसलिए TIME_WAIT connection हमेशा के लिए जमा रह जाते हैं।
प्रयोग के नतीजे
टीम ने overflow से पहले और बाद के 5-5 मिनट तक, प्रति सेकंड कई short-lived TCP connection बनाते हुए TIME_WAIT की संख्या देखी।
| चरण | स्थिति |
|---|---|
| overflow से पहले | TIME_WAIT ~200 पर स्थिर रहा (हर 30 सेकंड में सामान्य expiry) |
| overflow के तुरंत बाद | expiry रुक गई और TIME_WAIT monotonic increase में चला गया |
| connection बनाना रोकने के 84 सेकंड बाद | 0 होना चाहिए था, लेकिन TIME_WAIT उल्टा बढ़ा (2,828 → 2,837) |
| overflow के 9.5 घंटे बाद | Machine A: 4,888, Machine B: 8,217 — एक भी recover नहीं हुआ |
9.5 घंटे बाद SYN_SENT state वाले connection भी 3,000 से ज़्यादा जमा हो गए, और Machine B का load average 49.74 तक पहुंच गया।
किन environments पर असर
सामान्य consumer Mac अक्सर OS update के कारण 49 दिन से पहले reboot हो जाते हैं, इसलिए असर कम हो सकता है। लेकिन नीचे वाले environment high-risk हैं:
- लंबे समय तक बिना downtime चलने वाले server fleet
- macOS CI/CD build server (Jenkins, GitHub Actions self-hosted runner)
- Mac Pro workstation (लंबे rendering/compilation workload)
- remote-managed colocation Mac
- Mac mini build farm और test infrastructure
अभी और आगे की प्रतिक्रिया
टीम फिलहाल reboot के बिना freeze हुए tcp_now को सीधे ठीक करने वाला workaround बना रही है। तब तक के लिए अस्थायी उपाय सिर्फ एक है:
49 दिन 17 घंटे 2 मिनट 47 सेकंड से पहले reboot schedule करें।
ऐसे ऐतिहासिक bug जिनसे यह मिलता-जुलता है
यह bug integer overflow bugs की उसी पुरानी lineage का हिस्सा है: Windows 95/98 का 49.7-दिन crash, Year 2038 problem (Y2K38), GPS week number rollover, और Pac-Man का 256-stage killscreen — ये सभी इसी परिवार के उदाहरण हैं।
मूल लेख: Photon Blog, 2026.04.07
अभी कोई टिप्पणी नहीं है.