La bomba de tiempo de 49 días oculta en macOS: la historia completa del bug del kernel que detiene por completo el networking TCP
(photon.codes)Se descubrió un bug en el kernel XNU de macOS que provoca una parálisis total del networking TCP tras exactamente 49 días, 17 horas, 2 minutos y 47 segundos de funcionamiento continuo. La causa es un overflow de entero de 32 bits en el contador interno de timestamps TCP del kernel (tcp_now). ping sigue respondiendo, pero ya no se puede establecer ninguna conexión TCP nueva, y por ahora la única solución es reiniciar.
Cómo se descubrió
Photon operaba 24/7 una flota de servidores Mac que monitorea el estado del servicio de iMessage. El 30 de marzo de 2026, justo al cumplirse 49.7 días desde el último reinicio, varias máquinas empezaron silenciosamente a rechazar nuevas conexiones TCP. ping seguía funcionando y las conexiones existentes se mantenían, pero fallaba cualquier intento de abrir sockets nuevos.
Tras reiniciar para recuperar el servicio, el equipo eligió dos máquinas (A y B) que alcanzarían el mismo punto crítico en pocos días y diseñó un experimento en vivo.
Principio técnico del bug
El contador problemático tcp_now
En el kernel XNU, tcp_now es un entero sin signo de 32 bits que cuenta en milisegundos el tiempo transcurrido desde el arranque. El valor máximo que puede representar un entero de 32 bits es 4,294,967,295 ms, lo que equivale exactamente a 49 días, 17 horas, 2 minutos y 47 segundos.
¿Por qué el contador se “congela”?
El código de actualización de tcp_now tiene una guarda simple para “evitar que el reloj retroceda”:
if (tmp < current_tcp_now) {
os_atomic_cmpxchg(&tcp_now, tmp, current_tcp_now, ...);
}
En el momento del overflow, el current_tcp_now recién calculado vuelve a enrollarse cerca de 0, mientras que el tmp existente está cerca del valor máximo. Entonces la condición tmp < current_tcp_now queda falsa para siempre, así que tcp_now se queda detenido en ese valor. El reloj TCP del kernel se detuvo.
Por qué TIME_WAIT nunca expira
Cuando una conexión TCP se cierra, el kernel registra su hora de expiración como tcp_now + 30 segundos. Un recolector de basura recorre periódicamente estas entradas y libera la conexión si tcp_now >= hora de expiración. Pero si tcp_now se congela, esa condición nunca vuelve a ser verdadera, por lo que las conexiones en TIME_WAIT jamás se recolectan.
Resultados del experimento
El equipo observó la cantidad de conexiones en TIME_WAIT mientras generaba varias conexiones TCP de vida corta por segundo durante 5 minutos antes y 5 minutos después del overflow.
| Tramo | Estado |
|---|---|
| Antes del overflow | TIME_WAIT se mantenía estable en ~200 (expiración normal cada 30 segundos) |
| Justo después del overflow | La expiración se detiene y TIME_WAIT empieza a crecer de forma monotónica |
| 84 segundos después de detener la creación de conexiones | TIME_WAIT, que debería haber llegado a 0, en cambio aumentó (2,828 → 2,837) |
| 9.5 horas después del overflow | Machine A: 4,888, Machine B: 8,217 — no se recolectó ni una sola conexión |
Después de 9.5 horas, también se habían acumulado más de 3,000 conexiones en estado SYN_SENT, y el load average de Machine B se disparó hasta 49.74.
Entornos afectados
Las Mac de consumo general suelen reiniciarse antes de los 49 días por actualizaciones del sistema operativo, así que el impacto es menor. Pero los siguientes entornos tienen alto riesgo:
- Flotas de servidores con alta disponibilidad durante largos periodos
- Servidores macOS de build para CI/CD (Jenkins, runners self-hosted de GitHub Actions)
- Workstations Mac Pro (renderizado o compilación de larga duración)
- Mac en colocation administradas en forma remota
- Granjas de build con Mac mini e infraestructura de pruebas
Respuesta actual y futura
El equipo está desarrollando un workaround para corregir directamente tcp_now congelado sin reiniciar. Hasta entonces, solo hay una medida temporal:
Programa un reinicio antes de los 49 días, 17 horas, 2 minutos y 47 segundos.
Bugs históricos similares
Este bug pertenece a una larga línea histórica de bugs por overflow de enteros: el crash de 49.7 días de Windows 95/98, el problema del año 2038 (Y2K38), el rollover del número de semana de GPS y la killscreen del nivel 256 de Pac-Man pertenecen a la misma familia.
Original: Photon Blog, 2026.04.07
9 comentarios
Ahora macOS también cumple sus 49 días.
jajajajaja
zzzzz
Como se trata de un problema relacionado con el tiempo, me hace pensar en el Y2K... 🤖..
Los humanos repiten los mismos errores.
Así que de verdad hay que reiniciar antes de los 49 días.
En realidad, nunca se debería comparar el tiempo absoluto con
<...if ((int32_t)(tmp - current_tcp_now) < 0) {
os_atomic_cmpxchg(&tcp_now, tmp, current_tcp_now, ...);
}
Se tendría que hacer así, viendo la diferencia entre los dos valores... pero los humanos siempre terminamos cometiendo los mismos errores.
Viendo cosas así, capaz que en 2038 de verdad se arma un caos.
Vaya, esto de verdad no tiene sentido....
Entonces, ¿cómo es que las instancias Mac de AWS o GitHub no tuvieron problemas todo este tiempo...?