يمكن لملف نموذج بحجم 65 بايت أن يتسبب في توقف محرك الاستدلال الشهير Llama CPP بشكل مفاجئ. تؤدي هذه الحمولة الصغيرة إلى حدوث عملية قسمة على صفر داخل المحلل (parser)، مما ينتج عنه انهيار من نوع SIGFPE.

لماذا يمثل هذا الانهيار أهمية

ما الذي حدث؟

يقوم المحلل بقراءة البيانات الوصفية (metadata) للنموذج في هياكل C++ ويتحقق من أن كل بُعد للموتر (tensor dimension) هو "غير سالب". الصفر يستوفي هذا الشرط، لذا تجتاز عملية التحقق. ثم يستخدم السطر التالي من الكود هذا البُعد كمقسوم عليه في عملية حسابية تفترض أن القيمة موجبة. عندما يكون البُعد صفراً، تؤدي عملية القسمة إلى استثناء نقطة عائمة (SIGFPE) وتؤدي إلى إنهاء البرنامج.

غطت عملية التحقق نصف الثابت (invariant) المطلوب فقط: فقد منعت القيم السالبة ولكنها تجاهلت الصفر، وهو أمر غير آمن تماماً للعمليات الحسابية اللاحقة.

ما الذي يجب على المطورين فعله

  • عامل ملفات النماذج كملفات ثنائية (binaries). يؤدي تحميل النموذج إلى تحليل البايتات الخام وتحويلها إلى هياكل في الذاكرة، وهي نقطة حدودية كلاسيكية حيث يمكن للبيانات غير المفحوصة أن تتسبب في انهيار العملية أو ما هو أسوأ.
  • تجنب عمليات التحقق الجزئية. إن الشرط الذي يغطي جزءاً فقط من الثابت المطلوب يعطي شعوراً زائفاً بالأمان. في هذه الحالة، لم تكن عبارة "غير سالب" كافية؛ بل كان الكود بحاجة إلى شرط "موجب".
  • شكك في الافتراضات بعد كل عملية تحقق. عند ظهور اختبار للحدود، تحقق من أن الكود التالي لا يعتمد على خاصية أكثر صرامة.
  • استخدم أدوات الفحص العشوائي (fuzzing tools). اكتشف المؤلف الخطأ عن طريق تشغيل libFuzzer مع AddressSanitizer، والتي تقوم بتحوير المدخلات وتحديد العمليات غير القانونية مثل القسمة على صفر.

كيف تم تطبيق الإصلاح

يضيف الإصلاح حماية (guard) تتخطى عملية حساب التجاوز (overflow) عندما يكون البُعد مساوياً للصفر. يحافظ هذا الشرط الصغير على دعم الموترات ذات الحجم صفر المشروعة — والتي تُستخدم في بعض متغيرات النماذج للميزات الاختيارية — مع القضاء على مسار الانهيار.

الخلاصة: يمكن لملف واحد بحجم 65 بايت أن يعطل محرك استدلال واسع الانتشار؛ التحقق الشامل والفحص العشوائي المنهجي يحافظان على سلامة محملات النماذج.

المصدر: https://dev.to/harrisonsec/your-model-file-is-untrusted-input-1eap