اعتبارًا من عام 2016 ، كان حوالي 86٪ من جميع نقاط الضعف على Android مرتبطة بأمان الذاكرة. يتم استغلال معظم الثغرات الأمنية من قبل المهاجمين الذين يغيرون تدفق التحكم الطبيعي لتطبيق ما لأداء أنشطة ضارة عشوائية مع جميع امتيازات التطبيق المستغل. سلامة تدفق التحكم (CFI) هي آلية أمنية لا تسمح بإجراء تغييرات على الرسم البياني لتدفق التحكم الأصلي للثنائي المترجم ، مما يجعل تنفيذ مثل هذه الهجمات أكثر صعوبة.
في Android 8.1 ، قمنا بتمكين تطبيق LLVM لـ CFI في مكدس الوسائط. في Android 9 ، قمنا بتمكين CFI في المزيد من المكونات وكذلك النواة. يتم تشغيل System CFI بشكل افتراضي ولكنك تحتاج إلى تمكين kernel CFI.
يتطلب CFI الخاص بـ LLVM التجميع باستخدام تحسين وقت الارتباط (LTO) . يحافظ LTO على تمثيل رمز بت LLVM لملفات الكائنات حتى وقت الارتباط ، مما يسمح للمترجم بتوضيح سبب أفضل للتحسينات التي يمكن إجراؤها. يؤدي تمكين LTO إلى تقليل حجم الثنائي النهائي وتحسين الأداء ، ولكنه يزيد من وقت الترجمة. في الاختبار على Android ، ينتج عن الجمع بين LTO و CFI مقدار ضئيل من حجم الكود والأداء ؛ في حالات قليلة كلاهما تحسن.
لمزيد من التفاصيل الفنية حول CFI وكيف يتم التعامل مع فحوصات التحكم الأمامي الأخرى ، راجع وثائق تصميم LLVM .
الأمثلة والمصدر
يتم توفير CFI بواسطة المترجم ويضيف الأجهزة إلى الثنائي أثناء وقت الترجمة. نحن ندعم CFI في سلسلة أدوات Clang ونظام إنشاء Android في AOSP.
يتم تمكين CFI افتراضيًا لأجهزة Arm64 لمجموعة المكونات في /platform/build/target/product/cfi-common.mk
. يتم تمكينه أيضًا بشكل مباشر في مجموعة من ملفات makefiles / blueprint لمكونات الوسائط ، مثل /platform/frameworks/av/media/libmedia/Android.bp
و /platform/frameworks/av/cmds/stagefright/Android.mk
.
تطبيق نظام CFI
يتم تمكين CFI بشكل افتراضي إذا كنت تستخدم Clang ونظام إنشاء Android. نظرًا لأن CFI يساعد في الحفاظ على أمان مستخدمي Android ، فلا يجب تعطيله.
في الواقع ، نحن نشجعك بشدة على تمكين CFI للمكونات الإضافية. المرشحون المثاليون هم كود أصلي مميز ، أو كود أصلي يعالج مدخلات المستخدم غير الموثوق بها. إذا كنت تستخدم clang ونظام إنشاء Android ، فيمكنك تمكين CFI في مكونات جديدة عن طريق إضافة بضعة أسطر إلى ملفات makefiles أو ملفات المخطط.
دعم CFI في makefiles
لتمكين CFI في ملف إنشاء ، مثل /platform/frameworks/av/cmds/stagefright/Android.mk
، أضف:
LOCAL_SANITIZE := cfi # Optional features LOCAL_SANITIZE_DIAG := cfi LOCAL_SANITIZE_BLACKLIST := cfi_blacklist.txt
- تحدد
LOCAL_SANITIZE
CFI باعتباره المطهر أثناء البناء. - يقوم
LOCAL_SANITIZE_DIAG
بتشغيل وضع التشخيص لـ CFI. يطبع وضع التشخيص معلومات تصحيح أخطاء إضافية في logcat أثناء الأعطال ، وهو أمر مفيد أثناء تطوير واختبار البنيات الخاصة بك. تأكد من إزالة وضع التشخيص في إصدارات الإنتاج. - يسمح
LOCAL_SANITIZE_BLACKLIST
للمكونات بتعطيل أدوات CFI بشكل انتقائي للوظائف الفردية أو ملفات المصدر. يمكنك استخدام القائمة السوداء كحل أخير لإصلاح أي مشكلات تواجه المستخدم قد تكون موجودة بخلاف ذلك. لمزيد من التفاصيل ، راجع تعطيل CFI .
دعم CFI في ملفات المخطط
لتمكين CFI في ملف مخطط ، مثل /platform/frameworks/av/media/libmedia/Android.bp
، أضف:
sanitize: { cfi: true, diag: { cfi: true, }, blacklist: "cfi_blacklist.txt", },
استكشاف الأخطاء وإصلاحها
إذا كنت تقوم بتمكين CFI في مكونات جديدة ، فقد تواجه بعض المشكلات المتعلقة بأخطاء عدم تطابق نوع الوظيفة وأخطاء عدم تطابق نوع رمز التجميع .
تحدث أخطاء عدم تطابق نوع الوظيفة لأن CFI يقيد المكالمات غير المباشرة للانتقال فقط إلى الوظائف التي لها نفس النوع الديناميكي مثل النوع الثابت المستخدم في المكالمة. يقيد CFI مكالمات وظائف الأعضاء الظاهرية وغير الظاهرية للانتقال فقط إلى الكائنات التي تعد فئة مشتقة من النوع الثابت للكائن المستخدم لإجراء المكالمة. هذا يعني أنه عندما يكون لديك رمز ينتهك أيًا من هذه الافتراضات ، فإن الأجهزة التي يضيفها CFI ستجهض. على سبيل المثال ، يُظهر تتبع المكدس SIGABRT ويحتوي logcat على سطر حول تكامل تدفق التحكم لإيجاد عدم تطابق.
لإصلاح ذلك ، تأكد من أن الوظيفة التي تم استدعاؤها لها نفس النوع الذي تم الإعلان عنه بشكل ثابت. فيما يلي مثالان على CLs:
- البلوتوث : / c / platform / system / bt / + / 532377
- NFC : / c / platform / system / nfc / + / 527858
هناك مشكلة أخرى محتملة وهي محاولة تمكين CFI في التعليمات البرمجية التي تحتوي على استدعاءات غير مباشرة للتجميع. نظرًا لعدم كتابة رمز التجميع ، ينتج عن هذا عدم تطابق في النوع.
لإصلاح ذلك ، قم بإنشاء أغلفة التعليمات البرمجية الأصلية لكل استدعاء تجميع ، ومنح الأغلفة نفس توقيع الوظيفة مثل مؤشر الاستدعاء. يمكن للغلاف بعد ذلك الاتصال مباشرة برمز التجميع. نظرًا لأن الفروع المباشرة لا يتم تشغيلها بواسطة CFI (لا يمكن إعادة تعيينها في وقت التشغيل وبالتالي لا تشكل خطرًا أمنيًا) ، فسيؤدي ذلك إلى حل المشكلة.
إذا كان هناك عدد كبير جدًا من وظائف التجميع ولا يمكن إصلاحها جميعًا ، يمكنك أيضًا وضع قائمة سوداء بجميع الوظائف التي تحتوي على استدعاءات غير مباشرة للتجميع. لا ينصح بهذا لأنه يعطل عمليات فحص CFI على هذه الوظائف ، وبالتالي فتح سطح الهجوم.
تعطيل CFI
لم نلاحظ أي عبء في الأداء ، لذلك لن تحتاج إلى تعطيل CFI. ومع ذلك ، إذا كان هناك تأثير يواجه المستخدم ، فيمكنك تعطيل CFI بشكل انتقائي للوظائف الفردية أو ملفات المصدر من خلال توفير ملف القائمة السوداء لمعقم في وقت الترجمة. تقوم القائمة السوداء بإرشاد المترجم لتعطيل أجهزة CFI في مواقع محددة.
يوفر نظام إنشاء Android دعمًا للقوائم السوداء لكل مكون (مما يسمح لك باختيار ملفات المصدر أو الوظائف الفردية التي لن تتلقى أدوات CFI) لكل من Make و Soong. لمزيد من التفاصيل حول تنسيق ملف القائمة السوداء ، راجع مستندات Clang المنبع .
تصديق
حاليًا ، لا يوجد اختبار CTS خصيصًا لـ CFI. بدلاً من ذلك ، تأكد من اجتياز اختبارات CTS مع أو بدون تمكين CFI للتحقق من أن CFI لا يؤثر على الجهاز.