A bomba-relógio de 49 dias escondida no macOS — a história completa do bug de kernel que paralisa totalmente a rede TCP
(photon.codes)Foi descoberto um bug no kernel XNU do macOS em que a rede TCP fica completamente paralisada após exatos 49 dias, 17 horas, 2 minutos e 47 segundos de operação contínua. A causa é um overflow de inteiro de 32 bits no contador interno de timestamps TCP do kernel (tcp_now). O ping continua respondendo, mas torna-se impossível estabelecer novas conexões TCP, e no momento a única solução é reiniciar.
Como a falha foi descoberta
A Photon operava 24/7 uma frota de servidores Mac que monitorava o estado do serviço iMessage. Em 30 de março de 2026, exatamente 49,7 dias após a última reinicialização, várias máquinas começaram silenciosamente a recusar novas conexões TCP. O ping funcionava normalmente, e as conexões existentes permaneciam ativas, mas toda tentativa de abrir novos sockets falhava.
Depois de restaurar o serviço com uma reinicialização, a equipe selecionou duas máquinas (A e B) que alcançariam o mesmo ponto crítico em poucos dias e projetou um experimento ao vivo.
O mecanismo técnico do bug
O contador problemático tcp_now
No kernel XNU, tcp_now é um inteiro sem sinal de 32 bits que conta o tempo decorrido desde o boot em milissegundos. O valor máximo que 32 bits podem representar é 4.294.967.295ms — o que corresponde exatamente a 49 dias, 17 horas, 2 minutos e 47 segundos.
Por que o contador “congela”?
O código de atualização de tcp_now contém uma proteção simples para “impedir que o relógio ande para trás”:
if (tmp < current_tcp_now) {
os_atomic_cmpxchg(&tcp_now, tmp, current_tcp_now, ...);
}
No instante do overflow, o current_tcp_now recém-calculado volta a um valor próximo de 0, enquanto o tmp existente está próximo do valor máximo. A condição tmp < current_tcp_now se torna false para sempre, fazendo com que tcp_now fique travado naquele valor. O relógio TCP do kernel simplesmente para.
Por que o TIME_WAIT não expira
Quando uma conexão TCP é encerrada, o kernel registra o horário de expiração como tcp_now + 30 segundos. Periodicamente, o coletor de lixo faz uma varredura e libera a conexão quando tcp_now >= horário de expiração. Mas, quando tcp_now congela, essa condição nunca mais se torna verdadeira, e as conexões em TIME_WAIT jamais são coletadas.
Resultados do experimento
A equipe observou a quantidade de conexões em TIME_WAIT enquanto gerava, por 5 minutos antes e depois do overflow, várias conexões TCP de curta duração por segundo.
| Período | Estado |
|---|---|
| Antes do overflow | TIME_WAIT permanecia estável em ~200 conexões (expiração normal a cada 30 segundos) |
| Logo após o overflow | As expirações pararam e o TIME_WAIT começou a crescer monotonamente |
| 84 segundos após interromper a criação de conexões | O TIME_WAIT, que deveria cair para 0, na verdade aumentou (2.828 → 2.837) |
| 9,5 horas após o overflow | Machine A: 4.888, Machine B: 8.217 — nenhuma conexão foi coletada |
Após 9,5 horas, também havia mais de 3.000 conexões no estado SYN_SENT acumuladas, e o load average da Machine B subiu para 49,74.
Ambientes afetados
Macs de consumidores em geral sofrem menos impacto, porque muitas vezes reiniciam antes de 49 dias por causa de atualizações do sistema operacional. Mas os ambientes a seguir são de alto risco:
- Frotas de servidores com longo tempo de atividade sem interrupção
- Servidores macOS de CI/CD (Jenkins, runners self-hosted do GitHub Actions)
- Workstations Mac Pro (renderização e compilação de longa duração)
- Macs em colocation gerenciados remotamente
- Build farms e infraestrutura de testes com Mac mini
Resposta atual e próximos passos
A equipe está desenvolvendo no momento um workaround para corrigir diretamente o tcp_now congelado sem reiniciar. Até lá, existe apenas uma medida temporária:
Agende uma reinicialização antes de 49 dias, 17 horas, 2 minutos e 47 segundos.
Bugs históricos semelhantes
Esse bug pertence a uma longa linhagem de falhas por overflow de inteiro: o crash de 49,7 dias do Windows 95/98, o problema de 2038 (Y2K38), o rollover do número da semana do GPS e a killscreen da fase 256 de Pac-Man são todos da mesma família.
Original: Photon Blog, 2026.04.07
9 comentários
Ultimamente, até o macOS está cumprindo os 49 dias.
kkkkkkkk
zzzzz
Já que é um problema relacionado a tempo, isso me faz lembrar do Y2K.. 🤖..
Os seres humanos repetem os mesmos erros.
Então realmente precisa reiniciar antes de 49 dias.
Na verdade, nunca se deve comparar tempo diretamente com
<...if ((int32_t)(tmp - current_tcp_now) < 0) {
os_atomic_cmpxchg(&tcp_now, tmp, current_tcp_now, ...);
}
Ou seja, tem que verificar a diferença entre os dois valores assim... No fim, os humanos sempre acabam cometendo os mesmos erros.
Vendo esse tipo de coisa, acho que em 2038 pode dar uma confusão de verdade.
Uau, isso é realmente absurdo....
Como é que as instâncias Mac da AWS ou do GitHub não tiveram problemas até agora...?