
Harness de auditoria que testa se a classe de bug de recursão de desempacotamento Any da CVE-2026-0994 afeta o núcleo C do upb nos bindings protobuf de Ruby e PHP, com payloads ASan/UBSan.
Status: Concluída. Seis verificações de proteção contra recursão em três implementações independentes (núcleo upb compartilhado entre Ruby/PHP, implementação gerenciada separada do C#), todas falsificadas exceto a CVE do Python já pública e já corrigida contra a qual esta auditoria estava verificando. Nenhuma nova vulnerabilidade foi encontrada.
Continuação das CVEs confirmadas de recursão no desempacotamento de Any nos bindings Python e JavaScript do protobuf (mais recentemente CVE-2026-0994, um bug puro de Python em _ConvertAnyMessage do json_format.py, que recursava via methodcaller() em vez de ConvertMessage() e ignorava silenciosamente o contador de profundidade).
Pergunta: a mesma classe de bug existe no núcleo C upb embutido nas extensões nativas de Ruby e PHP?
Resposta curta: não. O caminho de decodificação JSON, o caminho de decodificação binária do wire e a implementação gerenciada independente em C# impõem corretamente seus limites de recursão em todos os casos testados aqui, incluindo um payload de estresse de 200.000 níveis executado com uma pilha de 1MB. Esta é uma hipótese falsificada com evidências, não uma vulnerabilidade — está registrada aqui como um resultado negativo limpo, da mesma forma que você registraria uma hipótese falsificada em qualquer outra linha de pesquisa.
As extensões nativas de Ruby e PHP do protobuf cada uma embutem uma amalgamação de arquivo único do núcleo C do upb (ruby-upb.c, php-upb.c) em vez de linkar uma biblioteca compartilhada. Esta auditoria compila esse arquivo exato como um alvo C autônomo — sem runtime Ruby ou PHP envolvido — inicializa um upb_DefPool com descritores de google.protobuf.Any / Struct / Value / ListValue, e aciona os pontos de entrada reais do decodificador (upb_JsonDecode, upb_Decode) diretamente com payloads adversariais, sob ASan/UBSan.
| Caminho | Proteção | Limite padrão | Resultado |
|---|---|---|---|
Decodificação JSON, jsondec_any (Ruby) | d->depth, verificado em jsondec_push | 64 | Falsificada — erro limpo em payload de 5000 níveis, deslocamento de bytes corresponde exatamente a ~64 níveis |
Decodificação binária do wire, upb_Decode (Ruby) | Decode_LimitDepth | 100 | Falsificada — kUpb_DecodeStatus_MaxDepthExceeded limpo no payload de fronteira de 60 níveis e no payload de estresse de 200.000 níveis, ambos sob uma pilha de 8MB e uma pilha de 1MB (aproximando uma thread Ruby não-principal) |
| Binding PHP | mesmas funções de proteção | mesmos | Falsificada por prova de identidade, não por uma execução separada — veja abaixo |
Decodificação JSON, JsonParser.MergeAny (C#, Google.Protobuf 3.36.1) | tokenizer.RecursionDepth, verificado em Merge() | 100 | Falsificada — confirmada em payload de 200 níveis; MergeAny constrói um novo JsonTokenizer via FromReplayedTokens a cada desempacotamento de Any, mas a contabilidade de profundidade propaga-se corretamente através dele |
Decodificação binária do wire, CodedInputStream/Value.Parser (C#, Google.Protobuf 3.36.1) | recursionDepth/recursionLimit no stream | 64 | Falsificada — InvalidProtocolBufferException limpa no payload de fronteira de 60 níveis (mesmos bytes de payload do teste de wire em Ruby, reutilizados diretamente) |
Nenhuma violação de ASan ou UBSan foi observada em nenhuma execução. Sem crash, sem travamento, sem esgotamento de pilha.
php-upb.c e ruby-upb.c diferem em ~1.964 linhas no total, mas jsondec_any, jsondec_push e as constantes de limite de profundidade do wire são idênticas byte a byte entre os dois arquivos (verify_php_identical.sh prova isso, não aceite por fé — execute-o). Como o código de proteção em si é comprovadamente o mesmo, o resultado do Ruby se transfere sem a necessidade de um harness redundante específico para PHP.
Quatro bindings testados (Ruby, PHP, C#, mais a CVE já pública do Python), todos falsificados exceto aquele que já havia sido corrigido upstream. Linhas de investigação ainda em aberto, nenhuma delas desta classe específica de bug:
utf8_range.c embutido.dotnet run -- wire <payload>) ainda não está integrado ao CI — apenas o teste C# em modo JSON está automatizado../fetch_source.sh # pins & clones protobuf @ ead3f0029facc43da13588132e9091bf9bd7a26f
./build.sh # compiles both harnesses w/ ASan+UBSan against the fetched source
./run_tests.sh # generates payloads, runs the full matrix, prints results
./verify_php_identical.sh # confirms the PHP claim above instead of asserting it
Requer: gcc, protoc (apt-get install protobuf-compiler), python3,
git. Compilado e verificado com gcc (Ubuntu 13.3.0-6ubuntu2~24.04.1) 13.3.0 e libprotoc 3.21.12 — versões diferentes podem se comportar
de forma diferente; se os seus resultados não corresponderem à tabela acima, isso é um dado, não
um bug na sua configuração. Descubra o motivo antes de assumir que é uma incompatibilidade de ferramentas.
third_party/ (obtido por fetch_source.sh) contém o código-fonte do protobuf do Google,
licenciado sob Apache-2.0, fixado no commit acima. Ele nunca
é commitado neste repositório — fetch_source.sh é a âncora de reprodutibilidade
em vez de incorporar a árvore de código-fonte de terceiros nesta.