审计工具,用于测试 CVE-2026-0994 Any 解包递归漏洞类是否影响 Ruby 和 PHP protobuf 绑定中 upb 的 C 核心,并带有 ASan/UBSan 载荷。
状态:已完成。 针对三个独立实现(Ruby/PHP 共享的 upb 核心、C# 独立的管理实现)的六项递归防护检查,除本次审计所对照的、已公开且已修补的 Python CVE 外,其余全部被证伪。未发现新的漏洞。
这是对 protobuf 的 Python 和 JavaScript 绑定中已确认的 Any 解包递归 CVE 的后续调查(最近的是 CVE-2026-0994,这是 json_format.py 中 _ConvertAnyMessage 的一个纯 Python 缺陷,它通过 methodcaller() 而非 ConvertMessage() 进行递归,并静默跳过了深度计数器)。
问题: 捆绑在 Ruby 和 PHP 原生扩展中的 C upb 核心是否存在同一类缺陷?
简短回答:没有。 JSON 解码路径、二进制线格式解码路径以及独立的管理 C# 实现,在本文测试的每一种情况下都正确地执行了各自的递归限制,包括在 1MB 栈下运行的 200,000 层压力载荷。这是一个有证据的证伪假设,而非漏洞——它作为一次干净的阴性结果记录在此,就像在任何其他研究线索中记录一个被证伪的假设一样。
Protobuf 的 Ruby 和 PHP 原生扩展各自内置了 upb C 核心的单文件合并版本(ruby-upb.c、php-upb.c),而非链接共享库。本次审计将该确切文件构建为独立的 C 目标——不涉及 Ruby 或 PHP 运行时——用 google.protobuf.Any / Struct / Value / ListValue 描述符引导一个 upb_DefPool,并在 ASan/UBSan 下直接用对抗性载荷驱动真实的解码器入口点(upb_JsonDecode、upb_Decode)。
| 路径 | 防护 | 默认限制 | 结果 |
|---|---|---|---|
JSON 解码,jsondec_any(Ruby) | d->depth,在 jsondec_push 中检查 | 64 | 已证伪——在 5000 层载荷下干净报错,字节偏移与约 64 层完全吻合 |
二进制线格式解码,upb_Decode(Ruby) | Decode_LimitDepth | 100 | 已证伪——在 60 层边界载荷和 200,000 层压力载荷下均干净返回 kUpb_DecodeStatus_MaxDepthExceeded,两者分别在 8MB 栈和 1MB 栈(近似非主 Ruby 线程)下测试 |
| PHP 绑定 | 相同的防护函数 | 相同 | 通过同一性证明被证伪,而非单独运行——见下文 |
JSON 解码,JsonParser.MergeAny(C#,Google.Protobuf 3.36.1) | tokenizer.RecursionDepth,在 Merge() 中检查 | 100 | 已证伪——在 200 层载荷下确认;MergeAny 每次 Any 解包都会通过 FromReplayedTokens 构造一个新的 JsonTokenizer,但深度核算能正确地贯穿其中 |
二进制线格式解码,CodedInputStream/Value.Parser(C#,Google.Protobuf 3.36.1) | 流上的 recursionDepth/recursionLimit | 64 | 已证伪——在 60 层边界载荷下干净抛出 InvalidProtocolBufferException(与 Ruby 线格式测试相同的载荷字节,直接复用) |
任何一次运行中均未观察到 ASan 或 UBSan 违规。没有崩溃,没有挂起,没有栈耗尽。
php-upb.c 和 ruby-upb.c 整体相差约 1,964 行,但 jsondec_any、jsondec_push 以及线格式深度限制常量在两个文件之间逐字节相同(verify_php_identical.sh 证明了这一点,不要盲目相信——去运行它)。由于防护代码本身可证明是相同的,Ruby 的结果无需冗余的 PHP 专用测试框架即可迁移适用。
测试了四个绑定(Ruby、PHP、C#,加上 Python 已公开的 CVE),除已在上游修补的那一个外全部被证伪。仍然开放的线索,均不属于这一特定缺陷类别:
utf8_range.c 验证。dotnet run -- wire <payload>)尚未接入 CI——目前只有 JSON 模式的 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
需要:gcc、protoc(apt-get install protobuf-compiler)、python3、
git。已针对 gcc (Ubuntu 13.3.0-6ubuntu2~24.04.1) 13.3.0 和 libprotoc 3.21.12 构建并验证——不同版本可能表现
不同;如果你的结果与上表不符,那是数据,而不是
你环境中的 bug。在假定是工具链不匹配之前,先查明原因。
third_party/(由 fetch_source.sh 获取)包含 Google 的
Apache-2.0 许可的 protobuf 源代码,固定到上述提交。它
从不提交到此仓库——fetch_source.sh 是可复现性
锚点,而不是将别人的源代码树 vendor 到这一个中。