• macOS का TCP timestamp counter(tcp_now) बूट के लगभग 49.7 दिन बाद 32-bit overflow के कारण आंतरिक TCP clock को रोक देता है
  • इसके कारण TIME_WAIT state में मौजूद connections expire नहीं होते और जमा होते रहते हैं, जिससे ephemeral ports release नहीं हो पाते
  • समय बीतने पर ephemeral port exhaustion के कारण सभी नए TCP connections fail हो जाते हैं, और केवल existing connections ही बने रहते हैं
  • ICMP(ping) सामान्य रूप से काम करता है, लेकिन TCP की पूरी functionality ठप हो जाती है और reboot के अलावा recovery संभव नहीं होती
  • लंबे समय तक चलने वाले macOS server·build machine·CI environment इस समस्या के 49 दिन 17 घंटे के चक्र के संपर्क में रहते हैं, और kernel fix आने तक periodic reboot की आवश्यकता होती है

पृष्ठभूमि: TCP की बुनियादी अवधारणा

  • TCP connection बंद होने पर तुरंत गायब नहीं होता, बल्कि TIME_WAIT state में जाता है; यह delayed packets को संभालने और reliable termination के लिए जरूरी चरण है
    • यह पुराने packets को नए connection के रूप में गलत समझे जाने से रोकता है, और अंतिम ACK खो जाने पर retransmission संभालने के लिए होता है
  • TIME_WAIT की अवधि 2 × MSL(Maximum Segment Lifetime) के रूप में परिभाषित है, और macOS में यह लगभग 30 सेकंड पर सेट है
  • MSL वह अधिकतम समय है जितने समय तक TCP segment network में जीवित रह सकता है; RFC 793 में इसे 2 मिनट बताया गया था, लेकिन आधुनिक systems में यह काफी कम रखा जाता है
  • 32-bit unsigned integer overflow वह स्थिति है जिसमें मान अधिकतम सीमा(4,294,967,295) से आगे जाने पर 0 पर लौट आता है; macOS का TCP timestamp(tcp_now) बूट के बाद millisecond unit में बढ़ने वाला 32-bit counter है, जिसमें 49 दिन 17 घंटे 2 मिनट 47.296 सेकंड बाद overflow होता है

खोज: 49.7 दिनों बाद TCP connections रुकने की घटना

  • Photon के iMessage monitoring के लिए उपयोग किए जाने वाले Mac servers 24/7 चल रहे थे, और 30 मार्च 2026 को बूट के ठीक 49.7 दिन बाद सभी नए TCP connections fail होने लगे
    • existing connections और ICMP(ping) सामान्य रूप से काम कर रहे थे, लेकिन नए TCP sockets बनाना संभव नहीं था
  • मूल कारण XNU kernel के TCP timestamp counter(tcp_now) का overflow था, जहां monotonic increase verification logic wraparound के बाद update को रोक देता है, जिससे आंतरिक TCP clock रुक जाती है
  • TIME_WAIT connections expire नहीं होते, इसलिए ephemeral ports release नहीं होते और जमा होते रहते हैं, और अंततः reboot के अलावा recovery संभव नहीं रहती
  • reboot के बाद यही घटना फिर 49.7 दिन के चक्र में दोहराई गई

प्रयोग डिज़ाइन: overflow से पहले और बाद में TCP behavior की तुलना

  • परिकल्पना: अगर overflow के बाद TIME_WAIT garbage collection रुक जाती है, तो overflow से पहले और बाद में short-lived TCP connection creation pattern में अंतर दिखना चाहिए
    • overflow से पहले: TIME_WAIT 30 सेकंड बाद सामान्य रूप से expire होता है
    • overflow के बाद: TIME_WAIT अनिश्चितकाल तक बना रहता है
  • तीन चरणों वाला test script चलाया गया
    1. Monitoring phase: overflow से 35 मिनट पहले से 5 मिनट पहले तक हर 10 सेकंड में TIME_WAIT की संख्या रिकॉर्ड की गई
    2. Burst phase: overflow से पहले और बाद के 10 मिनट तक हर 2 सेकंड में लगभग 15 छोटे TCP connections बनाए गए
    3. Observation phase: connection creation रोकने के बाद TIME_WAIT में बदलाव को monitor किया गया

परिणाम: overflow के बाद TIME_WAIT ठहर गया

  • overflow से पहले TIME_WAIT की संख्या 0~200 के बीच स्थिर रूप से घूमती रही और सामान्य cleanup behavior की पुष्टि हुई
  • overflow के तुरंत बाद TIME_WAIT की संख्या लगातार बढ़ने लगी और फिर कभी expire नहीं हुई
  • Machine B में 2,828 TIME_WAIT connections 84 सेकंड बाद भी एक भी recover नहीं हुए, और उसके बाद भी लगातार जमा होते रहे
  • Machine A में भी manual verification के अनुसार TIME_WAIT की संख्या monotonic रूप से बढ़ी और recovery असंभव रही

मूल कारण: XNU kernel में tcp_now का 32-bit overflow

  • tcp_now bsd/netinet/tcp_var.h में परिभाषित millisecond unit वाला 32-bit counter है, जो boot के बाद बीते समय को track करता है
  • calculate_tcp_clock() function में (uint32_t)now.tv_sec * 1000 calculation 49.7 दिन बाद अधिकतम मान से ऊपर चली जाती है और wraparound होता है
  • if (tmp < current_tcp_now) condition के कारण overflow के समय पुराना मान नए मान से बड़ा हो जाता है, इसलिए update block हो जाता है और tcp_now स्थायी रूप से रुक जाता है
  • TIME_WAIT expiration check tcp_now के आधार पर की जाती है, इसलिए clock रुकने पर expiration condition हमेशा false हो जाती है और cleanup असंभव हो जाता है

श्रृंखलाबद्ध प्रभाव: TCP की पूरी functionality ठप

  • कुछ मिनट बाद: TIME_WAIT cleanup रुक जाता है, और short-lived connections वाले workloads में धीरे-धीरे समस्या शुरू होती है
  • कुछ घंटे बाद: हजारों TIME_WAIT जमा हो जाते हैं, और ephemeral port exhaustion शुरू हो जाता है
  • port exhaustion के बाद: नए TCP connections SYN_SENT state में fail होने लगते हैं, जबकि existing connections बने रहते हैं
  • CPU load में तेज़ बढ़ोतरी: kernel लगातार TIME_WAIT queue scan करता रहता है, जिससे load बढ़ता है
  • आखिरकार TCP पूरी तरह ठप, जबकि ICMP सामान्य रूप से काम करता रहता है
  • recovery का एकमात्र तरीका reboot है, जिसके बाद 49.7 दिन की गिनती फिर से शुरू होती है

अतिरिक्त साक्ष्य और संबंधित मामले

  • RFC 7323 स्पष्ट करता है कि 1ms unit वाले 32-bit timestamp में sign bit wrapping लगभग हर 24.8 दिन में होता है
    • macOS के मामले में यह पूरी 32-bit overflow(49.7 दिन) की समस्या है, जो RFC में बताए गए remote timestamp issue से अलग एक local kernel defect है
  • Apple community और open source projects में समान symptoms की कई reports मिलीं
    • TCP connection नहीं बनना, ping सामान्य, केवल reboot से समाधान, और कई हफ्तों की uptime के बाद समस्या आना
    • Podman issue #12495 आदि में वही pattern देखा गया
  • समानताएँ: सिर्फ TCP fail, ICMP सामान्य, reboot आवश्यक, कई हफ्तों के अंतराल पर समस्या

प्रभाव का दायरा

  • 49 दिन 17 घंटे से अधिक लगातार चलने वाले macOS systems में यह हो सकता है
  • सामान्य users पर असर कम है, क्योंकि periodic updates के दौरान reboot हो जाता है
  • उच्च-जोखिम वाले environment
    • लंबे समय तक चलने वाला server fleet
    • macOS आधारित CI/CD build servers
    • Mac Pro workstations
    • remote-managed colocation Macs
    • build farm·test infrastructure के लिए Mac mini clusters

पुनरुत्पादन प्रक्रिया

  • boot time से overflow के संभावित समय की गणना करें
  • overflow से पहले और बाद TIME_WAIT count monitor करें
  • overflow के समय बड़ी संख्या में short-lived TCP connections बनाएँ
  • 2 मिनट बाद भी यदि TIME_WAIT count कम न हो, तो bug reproduction सफल माना जाए

9.5 घंटे बाद देखी गई system state

  • TIME_WAIT connections में एक भी cleanup नहीं हुआ और वे लगातार बढ़ते रहे
  • SYN_SENT state में fail हुए 3,000 से अधिक connections जमा हो गए
  • केवल existing connections बने रहे और नए connections संभव नहीं रहे
  • Machine B का average load 49.74 तक पहुँच गया, क्योंकि kernel TIME_WAIT queue scan करने में अत्यधिक CPU इस्तेमाल कर रहा था

निष्कर्ष

  • केवल एक 32-bit integer और if (tmp < current_tcp_now) condition 49.7 दिन बाद पूरे TCP को रोक देने वाला time bomb बन गए
  • यह ऐसा defect है जिसे development·testing·code review चरणों में पकड़ना मुश्किल है, और जो केवल वास्तविक production environments में सामने आता है
  • Photon ने कई servers पर वही behavior reproduce किया, और overflow से पहले सामान्य cleanup तथा बाद में TIME_WAIT accumulation स्पष्ट रूप से पुष्टि हुई
  • tcp_now रुकते ही kernel की TCP clock रुक जाती है; system ऊपर से सामान्य दिखता है, लेकिन TCP ports पूरी तरह खत्म हो जाते हैं
  • लंबे समय तक चलने वाले macOS systems के admins को 49 दिन 17 घंटे 2 मिनट 47 सेकंड याद रखना चाहिए, और reboot schedule समायोजित करना या kernel fix आने तक periodic reboot करना आवश्यक है
  • Photon फिलहाल reboot के बिना tcp_now को recover करने वाला workaround विकसित कर रहा है

अभी कोई टिप्पणी नहीं है.

अभी कोई टिप्पणी नहीं है.