سلامة التحكّم في التدفق في النواة

سلامة تدفق التحكّم (CFI) هي آلية أمان تمنع إجراء تغييرات على الرسم البياني الأصلي لتدفق التحكّم في ملف ثنائي مترجَم، ما يجعل تنفيذ هذه الهجمات أكثر صعوبة.

بدءًا من Android 9، يمكنك تفعيل CFI في النواة.

يتضمّن نواة Linux طريقتَين مختلفتَين لتنفيذ CFI:

  • في نظام التشغيل Linux 6.0 والإصدارات الأقدم، يتم استخدام Clang CFI الذي يعتمد على Clang LTO
  • في نظام التشغيل Linux 6.1 والإصدارات الأحدث، Clang KCFI

تتطلّب ميزة "التحكّم في التدفق المتكامل" في Clang التجميع باستخدام تحسين وقت الربط (LTO). تحتفظ ميزة LTO بتمثيل رمز LLVM الثنائي لملفات الكائنات حتى وقت الربط، ما يتيح للمترجم البرمجي تحديد التحسينات التي يمكن إجراؤها بشكل أفضل. أظهرت الاختبارات على Android أنّ الجمع بين LTO وCFI يؤدي إلى زيادة طفيفة في حجم الرمز البرمجي والأداء. ومع ذلك، يؤدي تفعيل LTO إلى زيادة مدّة تصميم النواة بشكل كبير.

لا يتطلّب Clang KCFI ربطًا في وقت التشغيل، لذا تستفيد نواة Android الأحدث من ميزة CFI بدون تكاليف إضافية في وقت الإنشاء.

التنفيذ

يتم التحكّم في CFI من خلال الخيار CONFIG_CFI_CLANG الذي يتيح إما Clang CFI أو Clang KCFI.

للحصول على مزيد من التفاصيل الفنية حول CFI وكيفية التعامل مع عمليات التحقّق الأخرى من التحكّم المسبق، يُرجى الاطّلاع على مستندات تصميم LLVM. يُشار إلى KCFI هناك باسم -fsanitize=kcfi.

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

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

للمساعدة في تصحيح أخطاء حالات تعذُّر CFI، فعِّل CONFIG_CFI_PERMISSIVE، الذي يعرض تحذيرًا بدلاً من التسبّب في حدوث ذعر النواة. يجب عدم استخدام الوضع المتساهل في مرحلة الإنتاج.

التحقق من صحة البيانات

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