
CVE-2026-0994 Any-unwrapping 재귀 버그 클래스가 Ruby 및 PHP protobuf 바인딩의 upb C 코어에 영향을 미치는지 ASan/UBSan 페이로드로 테스트하는 감사 하네스.
protobuf의 Python 및 JavaScript 바인딩에서 확인된 Any-언래핑 재귀 CVE(가장 최근에는 CVE-2026-0994, json_format.py의 _ConvertAnyMessage에서 발생한 순수 Python 버그로, ConvertMessage() 대신 methodcaller()를 통해 재귀하여 깊이 카운터를 조용히 건너뛰었던 문제)에 대한 후속 조사입니다.
질문: Ruby 및 PHP 네이티브 확장에 번들로 포함된 C upb 코어에도 동일한 버그 클래스가 존재하는가?
짧은 답변: 아니오. JSON 디코드 경로와 바이너리 와이어 디코드 경로 모두 여기서 테스트된 모든 케이스에서 재귀 제한을 올바르게 적용하며, 1MB 스택에서 실행된 200,000단계 스트레스 페이로드도 포함됩니다. 이는 증거와 함께 반증된 가설이지 취약점이 아닙니다 — 다른 연구 스레드에서 반증된 가설을 기록하듯, 여기에 깔끔한 부정적 결과로 기록합니다.
Protobuf의 Ruby 및 PHP 네이티브 확장은 각각 공유 라이브러리를 링크하는 대신 upb의 C 코어를 단일 파일 아말감(ruby-upb.c, php-upb.c)으로 벤더링합니다. 이 감사는 해당 파일을 정확히 독립 실행형 C 타겟으로 빌드합니다 — Ruby나 PHP 런타임은 관여하지 않습니다 — / / / 디스크립터로 을 부트스트랩하고, 실제 디코더 진입점(, )을 적대적 페이로드로 직접 구동하며, ASan/UBSan 하에서 실행합니다.
google.protobuf.AnyStructValueListValueupb_DefPoolupb_JsonDecodeupb_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 바인딩 | 동일한 가드 함수 | 동일 | 동일성 증명에 의해 반증됨, 별도 실행이 아님 — 아래 참조 |
어떤 실행에서도 ASan 또는 UBSan 위반이 관찰되지 않았습니다. 크래시, 행, 스택 고갈도 없습니다.
php-upb.c와 ruby-upb.c는 전체적으로 약 1,964줄 차이가 있지만, jsondec_any, jsondec_push, 그리고 와이어 깊이 제한 상수는 두 파일 간에 바이트 단위로 동일합니다(verify_php_identical.sh가 이를 증명합니다, 믿지 말고 직접 실행해 보세요). 가드 코드 자체가 증명 가능하게 동일하므로, Ruby 결과는 중복된 PHP 전용 하네스 없이도 전이됩니다.
JsonParser / CodedInputStream이 자체 RecursionLimit 처리를 가짐). 진정으로 테스트되지 않았으며, 이 저장소는 아직 이를 다루지 않습니다.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
필요 사항: 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에 대해 빌드 및 검증되었습니다 — 다른 버전은 다르게 동작할 수 있습니다; 결과가 위 표와 일치하지 않는다면, 그것은 데이터이지 설정의 버그가 아닙니다. 도구 불일치라고 가정하기 전에 이유를 알아내세요.
third_party/(fetch_source.sh가 가져옴)에는 Google의 Apache-2.0 라이선스 protobuf 소스가 포함되어 있으며, 위 커밋에 고정되어 있습니다. 이는 이 저장소에 절대 커밋되지 않습니다 — 다른 사람의 소스 트리를 이 저장소에 벤더링하는 대신 fetch_source.sh가 재현성의 기준점입니다.