
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.
Continuação dos CVEs confirmados de recursão de desempacotamento de Any nos bindings Python e JavaScript do protobuf (mais recentemente CVE-2026-0994, um bug puramente em Python no _ConvertAnyMessage do json_format.py, que recursava via methodcaller() em vez de ConvertMessage() e silenciosamente ignorava 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. Tanto o caminho de decodificação JSON quanto o caminho de decodificação binária do wire aplicam seus limites de recursão corretamente em todos os casos testados aqui, incluindo um payload de estresse de 200.000 níveis executado sob 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 | Guarda | Limite padrão | Resultado |
|---|---|---|---|
Decodificação JSON, jsondec_any (Ruby) | d->depth, verificado em jsondec_push | 64 | Falsificado — erro limpo em payload de 5000 níveis, deslocamento de byte corresponde exatamente a ~64 níveis |
Decodificação binária do wire, upb_Decode (Ruby) | Decode_LimitDepth | 100 | Falsificado — kUpb_DecodeStatus_MaxDepthExceeded limpo em payload de fronteira de 60 níveis e em 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 guarda | mesmo | Falsificado por prova de identidade, não por uma execução separada — veja abaixo |
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 byte-idênticas entre os dois arquivos (verify_php_identical.sh prova isso, não aceite por fé — execute-o). Como o código de guarda em si é provavelmente o mesmo, o resultado do Ruby se transfere sem precisar de um harness redundante específico para PHP.
JsonParser / CodedInputStream com seu próprio tratamento de RecursionLimit). Genuinamente não testado; este repositório ainda não o cobre.utf8_range.c../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 contra 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 seus resultados não corresponderem à tabela acima, isso é um dado, não um bug na sua configuração. Descubra o porquê antes de assumir que é uma incompatibilidade de ferramentas.
third_party/ (obtido por fetch_source.sh) contém o código-fonte protobuf da 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 embutir a árvore de código-fonte de outra pessoa nesta.