
أداة تدقيق تختبر ما إذا كانت فئة ثغرة التكرار غير المحدود لفك أي (Any-unwrapping recursion) CVE-2026-0994 تؤثر على نواة C الخاصة بـ upb في ارتباطات protobuf للغة Ruby وPHP، باستخدام حِمل ASan/UBSan.
الحالة: مكتمل. ستة فحوصات لحارس الاستدعاء الذاتي عبر ثلاثة تطبيقات مستقلة (نواة upb المشتركة بين Ruby/PHP، وتطبيق C# المُدار المنفصل)، جميعها دُحضت باستثناء ثغرة Python CVE العلنية والمُرقَّعة مسبقًا التي كان هذا التدقيق يتحقق منها. لم يتم العثور على أي ثغرات جديدة.
متابعة لثغرات CVE المؤكدة الخاصة بالاستدعاء الذاتي لفكّ تغليف Any في ارتباطات Python وJavaScript الخاصة بـ protobuf (وأحدثها CVE-2026-0994، وهو خطأ بلغة Python خالصة في _ConvertAnyMessage داخل json_format.py، والذي كان يستدعي نفسه عبر methodcaller() بدلاً من ConvertMessage() ويتجاوز عدّاد العمق بصمت).
السؤال: هل توجد نفس فئة الأخطاء في نواة upb المكتوبة بلغة C والمضمّنة في امتدادات Ruby وPHP الأصلية؟
الإجابة المختصرة: لا. مسار فك ترميز JSON، ومسار فك ترميز البيانات الثنائية على السلك، وتطبيق C# المُدار المستقل، جميعها تفرض حدود الاستدعاء الذاتي الخاصة بها بشكل صحيح في كل حالة اختُبرت هنا، بما في ذلك حمولة إجهاد بمستوى 200,000 تعمل ضمن مكدس بحجم 1MB. هذه فرضية دُحضت بالأدلة، وليست ثغرة — وهي مسجّلة هنا كنتيجة سلبية نظيفة، بالطريقة نفسها التي تسجّل بها فرضية مدحوضة في أي خيط بحثي آخر.
كل من امتدادي Ruby وPHP الأصليين لـ protobuf يضمّن نسخة مدمجة أحادية الملف من نواة upb المكتوبة بلغة C (ruby-upb.c، php-upb.c) بدلاً من الربط بمكتبة مشتركة. يبني هذا التدقيق ذلك الملف نفسه كهدف C مستقل — دون أي وقت تشغيل لـ Ruby أو PHP — ويهيّئ upb_DefPool بوصفات google.protobuf.Any / Struct / Value / ListValue، ويقود نقاط دخول فك الترميز الحقيقية (upb_JsonDecode، upb_Decode) مباشرة بحمولات عدائية، تحت ASan/UBSan.
| المسار | الحارس | الحد الافتراضي | النتيجة |
|---|---|---|---|
فك ترميز JSON، jsondec_any (Ruby) | d->depth، يُفحص في jsondec_push | 64 | مدحوضة — خطأ نظيف عند حمولة بمستوى 5000، وإزاحة البايت تطابق ~64 مستوى بدقة |
فك ترميز البيانات الثنائية على السلك، upb_Decode (Ruby) | Decode_LimitDepth | 100 | مدحوضة — kUpb_DecodeStatus_MaxDepthExceeded نظيف عند حمولة حدّية بمستوى 60 وعند حمولة إجهاد بمستوى 200,000، وكلاهما ضمن مكدس بحجم 8MB ومكدس بحجم 1MB (بمحاكاة خيط Ruby غير الرئيسي) |
| ارتباط PHP | نفس دوال الحارس | نفسها | مدحوضة بإثبات التطابق، وليس بتشغيل منفصل — انظر أدناه |
فك ترميز JSON، JsonParser.MergeAny (C#، Google.Protobuf 3.36.1) | tokenizer.RecursionDepth، يُفحص في Merge() | 100 | مدحوضة — مؤكدة عند حمولة بمستوى 200؛ يُنشئ MergeAny كائن JsonTokenizer جديدًا عبر FromReplayedTokens عند كل فكّ تغليف لـ Any، لكن حساب العمق ينتشر بشكل صحيح عبره |
فك ترميز البيانات الثنائية على السلك، CodedInputStream/Value.Parser (C#، Google.Protobuf 3.36.1) | recursionDepth/recursionLimit على التدفق | 64 | مدحوضة — InvalidProtocolBufferException نظيف عند حمولة حدّية بمستوى 60 (نفس بايتات الحمولة المستخدمة في اختبار السلك الخاص بـ 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 بعد — فقط اختبار C# في وضع JSON مؤتمت../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) على مصدر protobuf
التابع لـ Google المرخّص بموجب Apache-2.0، والمثبّت على الالتزام أعلاه. لا
يُودَع أبدًا في هذا المستودع — إذ يُعدّ fetch_source.sh مرتكزًا
للقابلية للتكرار بدلًا من تضمين شجرة مصدر شخص آخر داخل هذه الشجرة.