ذاكرة التنفيذ فقط (XOM) لثنائيات AArch64

يتم بشكل افتراضي وضع علامة على أقسام التعليمات البرمجية القابلة للتنفيذ لثنائيات نظام AArch64 للتنفيذ فقط (غير قابلة للقراءة) كتخفيف من حدة هجمات إعادة استخدام التعليمات البرمجية في الوقت المناسب. لم تعد التعليمات البرمجية التي تمزج البيانات والتعليمات البرمجية معًا والتعليمات البرمجية التي تفحص هذه الأقسام بشكل هادف (دون إعادة تعيين شرائح الذاكرة أولاً لتكون قابلة للقراءة) تعمل. تتأثر التطبيقات التي تحتوي على SDK مستهدف يبلغ 10 (مستوى واجهة برمجة التطبيقات 29 أو أعلى) إذا حاول التطبيق قراءة أقسام التعليمات البرمجية في مكتبات النظام التي تم تمكينها في ذاكرة التنفيذ فقط (XOM) في الذاكرة دون وضع علامة على القسم أولاً على أنه قابل للقراءة.

للاستفادة الكاملة من هذا التخفيف، يلزم دعم كل من الأجهزة والنواة. وبدون هذا الدعم، قد يتم تنفيذ التخفيف جزئيًا فقط. يحتوي Android 4.9 kernel المشترك على التصحيحات المناسبة لتوفير الدعم الكامل لهذا على أجهزة ARMv8.2.

تطبيق

تفترض ثنائيات AArch64 التي تم إنشاؤها بواسطة المترجم عدم اختلاط التعليمات البرمجية والبيانات. تفعيل هذه الخاصية لا يؤثر سلباً على أداء الجهاز.

بالنسبة للتعليمات البرمجية التي يجب أن تؤدي استبطانًا متعمدًا للذاكرة على مقاطعها القابلة للتنفيذ، فمن المستحسن استدعاء mprotect على مقاطع التعليمات البرمجية التي تتطلب الفحص للسماح لها بالقراءة، ثم إزالة إمكانية القراءة عند اكتمال الفحص.
يؤدي هذا التنفيذ إلى قراءة مقاطع الذاكرة التي تم وضع علامة عليها للتنفيذ فقط مما يؤدي إلى خطأ تجزئة ( SEGFAULT ). قد يحدث هذا نتيجة خطأ أو ثغرة أمنية أو بيانات مختلطة مع التعليمات البرمجية (التجميع الحرفي) أو الاستبطان المتعمد للذاكرة.

دعم الجهاز وتأثيره

الأجهزة التي تحتوي على أجهزة سابقة أو أنوية سابقة (أقل من 4.9) بدون التصحيحات المطلوبة قد لا تدعم هذه الميزة أو تستفيد منها بشكل كامل. الأجهزة التي لا تدعم kernel قد لا تفرض وصول المستخدم إلى ذاكرة التنفيذ فقط، ومع ذلك فإن كود kernel الذي يتحقق بشكل صريح مما إذا كانت الصفحة قابلة للقراءة قد يستمر في فرض هذه الخاصية، مثل process_vm_readv() .

يجب تعيين علامة kernel CONFIG_ARM64_UAO في kernel للتأكد من أن kernel يحترم صفحات أرض المستخدم التي تم وضع علامة "للتنفيذ فقط" عليها. قد لا تستفيد أجهزة ARMv8 السابقة، أو أجهزة ARMv8.2 مع تعطيل تجاوز وصول المستخدم (UAO)، بشكل كامل من هذا وقد تظل قادرة على قراءة صفحات التنفيذ فقط باستخدام مكالمات النظام.

إعادة هيكلة التعليمات البرمجية الموجودة

قد تحتوي التعليمات البرمجية التي تم نقلها من AArch32 على بيانات ورموز مختلطة، مما يتسبب في ظهور مشكلات. في كثير من الحالات، يكون إصلاح هذه المشكلات بسيطًا مثل نقل الثوابت إلى قسم .data في ملف التجميع.

قد يلزم إعادة هيكلة التجميع المكتوب بخط اليد لفصل الثوابت المجمعة محليًا.

أمثلة:

يجب ألا تواجه الثنائيات التي تم إنشاؤها بواسطة برنامج التحويل البرمجي Clang أي مشكلات تتعلق بخلط البيانات في التعليمات البرمجية. إذا تم تضمين التعليمات البرمجية التي تم إنشاؤها لمجموعة مترجم GNU (GCC) (من مكتبة ثابتة)، فافحص ثنائي الإخراج للتأكد من عدم تجميع الثوابت في أقسام التعليمات البرمجية.

إذا كان استبطان التعليمات البرمجية ضروريًا في أقسام التعليمات البرمجية القابلة للتنفيذ، فاتصل أولاً mprotect لوضع علامة على التعليمات البرمجية القابلة للقراءة. ثم بعد اكتمال العملية، اتصل بـ mprotect مرة أخرى لوضع علامة عليها كغير قابلة للقراءة.

تمكين

يتم تمكين التنفيذ فقط افتراضيًا لجميع الثنائيات 64 بت في نظام الإنشاء.

تعطيل

يمكنك تعطيل التنفيذ فقط على مستوى الوحدة النمطية، أو من خلال شجرة دليل فرعي بأكملها، أو عالميًا للبنية بأكملها.

يمكن تعطيل XOM للوحدات الفردية التي لا يمكن إعادة هيكلتها، أو التي تحتاج إلى قراءة التعليمات البرمجية القابلة للتنفيذ، عن طريق تعيين متغيرات LOCAL_XOM و xom على false .

// Android.mk
LOCAL_XOM := false

// Android.bp
cc_binary { // or other module types
   ...
   xom: false,
}

إذا تم تعطيل ذاكرة التنفيذ فقط في مكتبة ثابتة، فسيطبق نظام الإنشاء هذا على جميع الوحدات التابعة لتلك المكتبة الثابتة. يمكنك تجاوز ذلك باستخدام xom: true, .

لتعطيل ذاكرة التنفيذ فقط في دليل فرعي معين (على سبيل المثال، foo/bar/)، قم بتمرير القيمة إلى XOM_EXCLUDE_PATHS .

make -j XOM_EXCLUDE_PATHS=foo/bar

وبدلاً من ذلك، يمكنك تعيين المتغير PRODUCT_XOM_EXCLUDE_PATHS في تكوين المنتج الخاص بك.

يمكنك تعطيل الثنائيات المخصصة للتنفيذ فقط عالميًا عن طريق تمرير ENABLE_XOM=false إلى أمر make الخاص بك.

make -j ENABLE_XOM=false

تصديق

لا توجد اختبارات CTS أو اختبارات تحقق متاحة للذاكرة المخصصة للتنفيذ فقط. يمكنك التحقق من الثنائيات يدويًا باستخدام readelf والتحقق من إشارات المقطع.