Scudo هي أداة ديناميكية لتخصيص الذاكرة في وضع المستخدم، أو أداة لتخصيص الكومة، وهي مصمَّمة لتكون مرنة في مواجهة الثغرات الأمنية المرتبطة بالكومة (مثل تجاوز سعة المخزن المؤقت المستند إلى الكومة والاستخدام بعد التحرير والتحرير المزدوج) مع الحفاظ على الأداء. ويوفّر هذا البرنامج عناصر C الأساسية لتخصيص الذاكرة وإلغاء تخصيصها (مثل malloc وfree)، بالإضافة إلى عناصر C++ الأساسية (مثل new وdelete).
تُعدّ Scudo أداة للحدّ من أخطاء الذاكرة أكثر من كونها أداة متكاملة لرصدها، مثل AddressSanitizer (ASan).
منذ طرح الإصدار 11 من نظام التشغيل Android، يتم استخدام 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.
تتوفّر الخيارات التالية.
| Option | الإصدار التلقائي 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.