
Audit-Harness, das testet, ob die CVE-2026-0994-Rekursionsfehlerklasse beim Any-Unwrapping den C-Kern von upb in Ruby- und PHP-Protobuf-Bindings betrifft, mit ASan/UBSan-Payloads.
Folgeuntersuchung zu bestätigten Any-Entpackungs-Rekursions-CVEs in den Python- und JavaScript-Bindings von protobuf (zuletzt CVE-2026-0994, ein reiner Python-Bug in json_format.pys _ConvertAnyMessage, der über methodcaller() statt ConvertMessage() rekursierte und den Tiefenzähler stillschweigend übersprang).
Frage: Existiert dieselbe Fehlerklasse im C-upb-Kern, der in die nativen Ruby- und PHP-Erweiterungen eingebettet ist?
Kurze Antwort: nein. Sowohl der JSON-Dekodierungspfad als auch der binäre Wire-Dekodierungspfad erzwingen ihre Rekursionslimits korrekt unter jedem hier getesteten Fall, einschließlich einer 200.000-stufigen Stress-Nutzlast, die unter einem 1MB-Stack ausgeführt wurde. Dies ist eine falsifizierte Hypothese mit Belegen, keine Schwachstelle — sie wird hier als sauberes negatives Ergebnis festgehalten, so wie man eine falsifizierte Hypothese in jedem anderen Forschungsstrang protokollieren würde.
Die nativen Ruby- und PHP-Erweiterungen von Protobuf bündeln jeweils eine Einzeldatei-Amalgamation des C-Kerns von upb (ruby-upb.c, php-upb.c), anstatt eine Shared Library zu linken. Dieses Audit baut genau diese Datei als eigenständiges C-Target — ohne Ruby- oder PHP-Laufzeit — initialisiert einen upb_DefPool mit google.protobuf.Any / Struct / Value / ListValue-Deskriptoren und steuert die echten Decoder-Einstiegspunkte (upb_JsonDecode, upb_Decode) direkt mit adversarialen Nutzlasten an, unter ASan/UBSan.
| Pfad | Guard | Standardlimit | Ergebnis |
|---|---|---|---|
JSON-Dekodierung, jsondec_any (Ruby) | d->depth, geprüft in jsondec_push | 64 | Falsifiziert — sauberer Fehler bei 5000-stufiger Nutzlast, Byte-Offset entspricht exakt ~64 Ebenen |
Binäre Wire-Dekodierung, upb_Decode (Ruby) | Decode_LimitDepth | 100 | Falsifiziert — sauberes kUpb_DecodeStatus_MaxDepthExceeded bei 60-stufiger Grenznutzlast und bei 200.000-stufiger Stress-Nutzlast, beide unter einem 8MB-Stack und einem 1MB-Stack (angenähert an einen Nicht-Main-Ruby-Thread) |
| PHP-Binding | dieselben Guard-Funktionen | dieselben | Falsifiziert durch Identitätsnachweis, kein separater Lauf — siehe unten |
In keinem Lauf wurde eine ASan- oder UBSan-Verletzung beobachtet. Kein Absturz, kein Hänger, keine Stack-Erschöpfung.
php-upb.c und ruby-upb.c unterscheiden sich insgesamt um ~1.964 Zeilen, aber jsondec_any, jsondec_push und die Wire-Tiefenlimit-Konstanten sind zwischen den beiden Dateien byte-identisch (verify_php_identical.sh beweist dies — nimm es nicht auf Treu und Glauben an, führe es aus). Da der Guard-Code selbst nachweislich derselbe ist, überträgt sich das Ruby-Ergebnis, ohne dass ein redundanter PHP-spezifischer Harness benötigt wird.
JsonParser / CodedInputStream mit eigener RecursionLimit-Behandlung). Wirklich ungetestet; dieses Repo deckt es noch nicht ab.utf8_range.c-Validierung../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
Erfordert: gcc, protoc (apt-get install protobuf-compiler), python3, git. Gebaut und verifiziert gegen gcc (Ubuntu 13.3.0-6ubuntu2~24.04.1) 13.3.0 und libprotoc 3.21.12 — andere Versionen können sich anders verhalten; falls deine Ergebnisse nicht mit der obigen Tabelle übereinstimmen, sind das Daten, kein Bug in deinem Setup. Finde heraus, warum, bevor du annimmst, es sei eine Tooling-Diskrepanz.
third_party/ (abgerufen durch fetch_source.sh) enthält Googles Apache-2.0-lizenzierten protobuf-Quellcode, gepinnt auf den obigen Commit. Er wird niemals in dieses Repo committet — fetch_source.sh ist der Reproduzierbarkeitsanker, anstatt den Quellbaum eines anderen in diesen zu vendorn.