Pular para o conteúdo principal
Todos os estudos de caso
SDK de nuvem · C++ · 2026

Dois Bugs no Parser DateTime
do AWS SDK for C++

Depois do decodificador Base64, apontamos o ESBMC para os parsers de timestamp do AWS SDK for C++ e reportamos mais dois defeitos: acumulação de dígitos sem limite, que estoura os acumuladores int dos campos, e uma conversão sem verificação de faixa, que reportava datas fora do intervalo como parsing bem-sucedido. A AWS confirmou os dois, incorporou o patch que enviamos e publicou a correção no PR #3896, liberado no SDK 1.11.877.

2

bugs de parsing de timestamp que reportamos, confirmados e corrigidos pela AWS no PR #3896

3

parsers de data endurecidos: RFC822, ISO-8601 e ISO-8601 Basic

1.11.877

versão do AWS SDK for C++ que traz a correção, publicada em 2026-08-24

12

testes de regressão adicionados upstream junto com a correção

Contexto

Aws::Utils::DateTime é o tipo de timestamp do AWS SDK for C++, e quase nada que uma aplicação faça com a AWS escapa dele. Prazos de validade de credenciais, timestamps de assinatura de requisição, cabeçalhos Last-Modified do S3 e todo campo com data em toda resposta de serviço passam por um dos seus três parsers: RFC822, ISO-8601 e ISO-8601 Basic. Os três operam sobre bytes que chegaram pela rede.

Cada parser é uma máquina de estados escrita à mão, que percorre a string um caractere por vez. Os campos são acumulados dígito a dígito, valor = valor * 10 + (c - '0'), e a máquina muda de estado ao encontrar um delimitador. Esse formato é compacto e rápido, e tem uma fraqueza característica: o laço é guiado por onde está o delimitador, não pela largura permitida do campo.

Abordagem

Analisamos os parsers com o ESBMC, nosso verificador de modelos de software, usando a mesma técnica que produziu os achados do Base64: em vez de alimentar os parsers com uma lista de strings de timestamp, nós os conduzimos com entrada simbólica e perguntamos ao solver se alguma string até um dado limite poderia alcançar um estouro aritmético ou um resultado silenciosamente errado.

O parsing de timestamps é um bom alvo para isso. As entradas são curtas, o espaço de estados é pequeno, e as propriedades de interesse são exatamente as que um verificador de modelos limitado decide diretamente: um acumulador sai da faixa do seu tipo, e uma conversão produz um valor que quem chama vai ler como válido sem que ele seja.

Resultados

Acumulação de dígitos sem limite, estourando os acumuladores int. Nada limitava quantos dígitos um campo guiado por delimitador podia absorver, então um timestamp como Wed, 99999999999999999999 Oct 2002 08:00:00 GMT leva o acumulador do dia para além de INT_MAX. Estouro de inteiro com sinal é comportamento indefinido em C++ ([expr.pre]/4), de modo que o que o parser faz a partir daí não é definido pela linguagem. O mesmo padrão valia para os campos de ano, mês, hora, minuto e segundo, nos três parsers. Enviamos o patch que limita cada acumulador à largura do seu campo: dois dígitos para dia, mês, hora, minuto e segundo, quatro para o ano.

Datas fora da faixa reportadas como parsing bem-sucedido. Separadamente, ConvertTimestampStringToTimePoint entregava o valor obtido a std::chrono::system_clock::from_time_t sem verificação de faixa. Essa conversão escala os segundos até o período de tique do relógio, o que, num relógio de nanossegundos, deixa a representação int64_t cobrindo apenas de cerca de 1677 a 2262. Uma data fora dessa janela estourava, e o valor errado resultante era devolvido a quem chamou como parsing bem-sucedido. A correção rejeita timestamps fora da faixa antes de converter e deriva a janela do relógio da plataforma, em vez de fixá-la no código.

O sentinela de "nunca expira" é o caso que dói. Fri, 31 Dec 9999 23:59:59 GMT é um marcador convencional de "nunca expira" em código próximo do HTTP, e está bem fora da faixa de um relógio de nanossegundos. Antes da correção ele era "parseado com sucesso" para um valor sem relação alguma com o ano 9999, que é exatamente o modo de falha errado para um timestamp que quem chama vai comparar com a hora atual para decidir se algo expirou. Depois da correção, WasParseSuccessful() retorna falso e quem chama consegue ver que o valor não é utilizável.

Confirmados e corrigidos upstream no PR #3896, integrado em 2026-08-24 e publicado no AWS SDK for C++ 1.11.877 no mesmo dia. O PR traz 12 novos testes de regressão fixando o comportamento, incluindo ida e volta nas fronteiras 2262-04-11 e 1677-09-22 e a rejeição de campos de dia com 9, 11 e 20 dígitos. A AWS credita o relato e o patch de largura de campo na mensagem de commit.

Se você usa o SDK

Atualize para o AWS SDK for C++ 1.11.877 ou posterior. Vale notar que a segunda correção muda um comportamento observável, e não apenas endurece um caminho interno: um timestamp fora da faixa do relógio do sistema agora resulta em parsing inválido, em vez de produzir um valor errado. Se o seu código faz parsing de sentinelas muito distantes no futuro e não verifica WasParseSuccessful(), a atualização vai expor isso, o que é o objetivo, mas convém saber antes da troca de versão, e não depois.

O que isso significa

Os dois defeitos são de naturezas diferentes, e só um deles é do tipo que uma ferramenta de segurança de memória apontaria. A acumulação de dígitos é comportamento indefinido, e um sanitizador poderia capturá-la dada a entrada certa. O bug de conversão não produz travamento nem diagnóstico: a função retorna, a verificação de sucesso de quem chamou passa, e o número errado se propaga. A verificação de modelos limitada trata os dois do mesmo jeito, porque ambos são apenas propriedades a decidir sobre o espaço de entradas, e nenhum depende de alguém ter adivinhado a entrada ao escrever um teste.

É também o segundo trabalho sobre a mesma base de código, e essa é a parte que vale generalizar. Uma vez modelado um decodificador ou um parser, o próximo da mesma biblioteca custa bem menos, e os achados se acumulam. Rotinas pequenas e autocontidas que ficam sobre bytes não confiáveis são onde essa técnica se paga mais rápido.

Referências

  1. aws/aws-sdk-cpp PR #3896, "Validate DateTime range and bound parser field widths (defense in depth)" (integrado em 2026-08-24). github.com/aws/aws-sdk-cpp/pull/3896
  2. aws/aws-sdk-cpp versão 1.11.877 (2026-08-24), a primeira a trazer a correção. github.com/aws/aws-sdk-cpp/releases/tag/1.11.877
  3. Nosso trabalho anterior no mesmo SDK: dois CVEs de segurança de memória no Base64, boletim de segurança da AWS 2026-080. Leia o estudo de caso
  4. ESBMC, o verificador de modelos limitado de código aberto usado na análise. github.com/esbmc/esbmc

Nota. Os problemas foram reportados por Lucas Carvalho Cordeiro e Rafael Sá Menezes (University of Manchester), creditados nominalmente na mensagem de commit upstream. A CRC Ltd não mantém parceria comercial com a AWS e a análise não foi encomendada pela AWS; os achados passaram pelo processo de divulgação coordenada de vulnerabilidades da AWS. A AWS classificou a correção como defesa em profundidade e não atribuiu CVE a nenhum dos dois problemas.