Scudo

‫Scudo هي أداة ديناميكية لتخصيص الذاكرة في وضع المستخدم، أو أداة لتخصيص الكومة، وهي مصمَّمة لتكون مرنة في مواجهة الثغرات الأمنية ذات الصلة بالكومة (مثل تجاوز سعة المخزن المؤقت المستند إلى الكومة والاستخدام بعد التحرير والتحرير المزدوج) مع الحفاظ على الأداء. توفّر هذه المكتبة عناصر C الأساسية لتخصيص الذاكرة وإلغاء تخصيصها (مثل malloc وfree)، بالإضافة إلى عناصر C++ الأساسية (مثل new وdelete).

تُعدّ Scudo أداة للحدّ من أخطاء الذاكرة أكثر من كونها أداة متكاملة لرصدها، مثل AddressSanitizer (ASan).

منذ إصدار Android 11، يتم استخدام scudo مع جميع الرموز البرمجية الأصلية (باستثناء الأجهزة ذات الذاكرة المنخفضة التي لا يزال يتم فيها استخدام jemalloc). في وقت التشغيل، تتولّى Scudo معالجة جميع عمليات تخصيص الذاكرة وإلغاء تخصيصها في الذاكرة الأصلية لجميع الملفات التنفيذية وتبعيات المكتبة، ويتم إيقاف العملية إذا تم رصد تلف أو سلوك مشبوه في الذاكرة.

‫Scudo هو برنامج مفتوح المصدر وهو جزء من مشروع compiler-rt في LLVM. تتوفّر المستندات على الرابط https://llvm.org/docs/ScudoHardenedAllocator.html. يتم شحن وقت تشغيل Scudo كجزء من سلسلة أدوات Android، وتمت إضافة دعم إلى Soong وMake للسماح بتفعيل أداة التخصيص بسهولة في ملف ثنائي.

يمكنك تفعيل أو إيقاف إجراءات التخفيف الإضافية ضمن أداة التخصيص باستخدام الخيارات الموضّحة أدناه.

التخصيص

يمكن تحديد بعض مَعلمات أداة التخصيص على أساس كل عملية بعدة طرق:

  • بشكل ثابت: حدِّد دالة __scudo_default_options في البرنامج تعرض سلسلة الخيارات التي سيتم تحليلها. يجب أن يتضمّن هذا الإجراء النموذج الأوّلي التالي: extern "C" const char *__scudo_default_options().
  • بشكل ديناميكي: استخدِم متغيّر البيئة SCUDO_OPTIONS الذي يحتوي على سلسلة الخيارات المطلوب تحليلها. تتجاوز الخيارات المحدّدة بهذه الطريقة أي تعريف تم إجراؤه من خلال __scudo_default_options.

تتوفّر الخيارات التالية.

خيار الإصدار التلقائي 64 بت الإعداد التلقائي لنظام 32 بت الوصف
QuarantineSizeKb 256 64 حجم الحجر الصحي (بالكيلوبايت) المستخدَم لتأخير إلغاء التخصيص الفعلي للأجزاء. قد يؤدي انخفاض القيمة إلى تقليل استخدام الذاكرة، ولكنّه سيقلّل من فعالية إجراءات التخفيف، أما القيمة السلبية فستعود إلى القيم التلقائية. يؤدي ضبط كل من هذا الإعداد وThreadLocalQuarantineSizeKb على صفر إلى إيقاف العزل التام.
QuarantineChunksUpToSize 2048 512 حجم البيانات (بالبايت) الذي يمكن عزله.
ThreadLocalQuarantineSizeKb 64 16 حجم ذاكرة التخزين المؤقت لكل سلسلة محادثات (بالكيلوبايت) المستخدمة لإيقاف الحجر الصحي العام قد يؤدي استخدام قيمة أقل إلى تقليل استخدام الذاكرة، ولكن قد يؤدي إلى زيادة التنازع على الحجر الصحي العام. يؤدي ضبط كل من هذا الخيار وQuarantineSizeKb على صفر إلى إيقاف الحجر الصحي بالكامل.
DeallocationTypeMismatch false false تفعيل إعداد تقارير الأخطاء في malloc/delete وnew/free وnew/delete[]
DeleteSizeMismatch true true تتيح هذه السمة إعداد تقارير الأخطاء في حال عدم تطابق أحجام عمليات الإضافة والحذف.
ZeroContents false false تتيح هذه السمة محتوى الأجزاء الصفرية عند التخصيص وإلغاء التخصيص.
allocator_may_return_null false false تحدّد هذه السمة أنّه يمكن للمخصّص عرض قيمة فارغة عند حدوث خطأ قابل للاسترداد، بدلاً من إنهاء العملية.
hard_rss_limit_mb 0 0 عندما يصل حجم RSS للعملية إلى هذا الحدّ، يتم إنهاء العملية.
soft_rss_limit_mb 0 0 عندما يصل حجم RSS للعملية إلى هذا الحدّ، يتعذّر إجراء المزيد من عمليات التخصيص أو يتم عرض الخطأ null (حسب قيمة allocator_may_return_null)، إلى أن ينخفض حجم RSS مجددًا للسماح بعمليات تخصيص جديدة.
allocator_release_to_os_interval_ms 5000 لا ينطبق يؤثّر ذلك في أداة تخصيص 64 بت فقط. في حال ضبط هذا الخيار، يحاول المتصفّح تحرير الذاكرة غير المستخدَمة لنظام التشغيل، ولكن ليس أكثر من هذا الفاصل الزمني (بالملّي ثانية). إذا كانت القيمة سالبة، لن يتم تحرير الذاكرة لنظام التشغيل.
abort_on_error true true في حال ضبط هذا الخيار، ستطلب الأداة abort() بدلاً من _exit() بعد طباعة رسالة الخطأ.

التحقُّق

في الوقت الحالي، لا تتوفّر اختبارات CTS مخصّصة لـ Scudo. بدلاً من ذلك، تأكَّد من اجتياز اختبارات CTS سواء كانت Scudo مفعَّلة أو غير مفعَّلة لبرنامج ثنائي معيّن للتحقّق من أنّها لا تؤثّر في الجهاز.

تحديد المشاكل وحلّها

في حال رصد مشكلة لا يمكن استردادها، يعرض برنامج التخصيص رسالة خطأ في واصف الخطأ العادي ثم ينهي العملية. تتم إضافة عمليات تتبُّع تسلسل استدعاء الدوال البرمجية التي تؤدي إلى الإنهاء في سجلّ النظام. يبدأ الناتج عادةً بالرمز Scudo ERROR: متبوعًا بملخّص قصير للمشكلة مع أي مؤشرات.

في ما يلي قائمة برسائل الخطأ الحالية وأسبابها المحتملة:

  • corrupted chunk header: تعذّر التحقّق من صحة المجموع الاختباري لعنوان الجزء. من المحتمل أن يكون ذلك بسبب أحد الأمرين التاليين: تم استبدال العنوان (جزئيًا أو كليًا)، أو أنّ المؤشر الذي تم تمريره إلى الدالة ليس جزءًا.
  • race on chunk header: تحاول سلسلتا محادثات مختلفتان تعديل العنوان نفسه في الوقت نفسه. ويشير ذلك عادةً إلى حدوث حالة سباق أو عدم توفّر قفل عام عند تنفيذ عمليات على هذا الجزء.
  • invalid chunk state: لا تكون البيانات في الحالة المتوقّعة لإجراء عملية معيّنة، مثلاً، لا يتم تخصيصها عند محاولة تحريرها، أو لا يتم عزلها عند محاولة إعادة استخدامها. ويُعدّ التحرير المزدوج السبب الشائع لحدوث هذا الخطأ.
  • misaligned pointer: يتم فرض متطلبات المحاذاة الأساسية بشكل صارم: 8 بايت على الأنظمة الأساسية 32 بت و16 بايت على الأنظمة الأساسية 64 بت. إذا لم يتوافق المؤشر الذي تم تمريره إلى وظائفنا مع هذه المتطلبات، يكون المؤشر الذي تم تمريره إلى إحدى الوظائف غير متوافق.
  • allocation type mismatch: عند تفعيل هذا الخيار، يجب أن تتطابق وظيفة إلغاء التخصيص التي يتم استدعاؤها على جزء مع نوع الوظيفة التي تم استدعاؤها لتخصيصه. ويمكن أن يؤدي هذا النوع من عدم التطابق إلى حدوث مشاكل أمنية.
  • invalid sized delete: عند استخدام عامل حذف C++14 ذي الحجم، وتفعيل عملية التحقّق الاختيارية، يحدث عدم تطابق بين الحجم الذي تم تمريره عند إلغاء تخصيص جزء والحجم المطلوب عند تخصيصه. ويكون ذلك عادةً بسبب مشكلة في المترجم أو خطأ في نوع البيانات في الكائن الذي يتم إلغاء تخصيصه.
  • RSS limit exhausted: تم تجاوز الحد الأقصى المحدّد اختياريًا لخلاصة RSS.

إذا كنت بصدد تصحيح خطأ في نظام التشغيل نفسه، يمكنك استخدام إصدار نظام التشغيل HWASan. إذا كنت بصدد تصحيح خطأ في تطبيق، يمكنك أيضًا استخدام إصدار تطبيق HWASan.