يقدّم "المشروع المفتوح المصدر لنظام Android" (AOSP) سياسة أساسية قوية ل التطبيقات والخدمات الشائعة على جميع أجهزة Android. يُجري المساهمون في AOSP تحسينات على هذه السياسة بانتظام. من المتوقّع أن تشكّل السياسة الأساسية حوالي %90 إلى %95 من السياسة النهائية على الجهاز، مع أنّ عمليات تخصيص الخاصة بالجهاز تشكّل النسبة المتبقية التي تتراوح بين %5 و%10. تركّز هذه المقالة على هذه التخصيصات الخاصة بالأجهزة وكيفية كتابة سياسة خاصة بالجهاز و بعض المزالق التي يجب تجنّبها على طول الطريق.
إعداد الجهاز
أثناء كتابة سياسة خاصة بالجهاز، اتّبِع الخطوات التالية:
التشغيل في الوضع المتساهِل
عندما يكون الجهاز في الوضع المتساهل، يتم تسجيل عمليات الرفض ولكن لا يتم فرضها. يُعدّ "الوضع المرخّص" مهمًا لسببين:
- يضمن الوضع المرخّص عدم تأخُّر مهام إعداد الجهاز المبكرة الأخرى بسبب إعداد السياسة.
- قد تحجب الرفض القسري حالات الرفض الأخرى. على سبيل المثال، يتطلّب الوصول إلى الملف عادةً البحث في الدليل وفتح الملف ثم قراءته. في وضع التنفيذ، لن يحدث سوى رفض البحث في الدليل. يضمن الوضع المرخّص ظهور جميع عمليات الرفض.
إنّ أبسط طريقة لوضع جهاز في الوضع المرخّص هي استخدام
سطر command kernel. يمكن إضافة هذا الإجراء إلى ملف BoardConfig.mk
على الجهاز:
platform/device/<vendor>/<target>/BoardConfig.mk
.
بعد تعديل سطر الأوامر، نفِّذ make clean
، ثم
make bootimage
، وفلش صورة التمهيد الجديدة.
بعد ذلك، أكِّد الوضع المرخّص باستخدام:
adb shell getenforce
أسبوعان هو مدة معقولة للبقاء في الوضع المسموح به بشكل عام. بعد معالجة معظم حالات الرفض، انتقِل إلى وضع التنفيذ مجددًا و عالج الأخطاء عند ظهورها. يمكن وضع النطاقات التي لا تزال تُصدر عمليات رفض أو الخدمات التي لا تزال في مرحلة تطوير مكثّفة مؤقتًا في الوضع المتساهل، ولكن يجب إعادتها إلى الوضع الصارم في أقرب وقت ممكن.
فرض السياسة مبكرًا
في وضع فرض القواعد، يتم تسجيل عمليات الرفض وفرضها. من أفضل الممارسات ضبط جهازك على وضع التنفيذ في أقرب وقت ممكن. غالبًا ما يؤدي الانتظار لإنشاء سياسة خاصة بالأجهزة وفرضها إلى ظهور أخطاء في المنتج وتقديم تجربته السيئة للمستخدم. ابدأ مبكرًا بما يكفي للمشاركة في مرحلة الاختبار الداخلي وضمان تغطية الاختبار الكامل للوظائف في الاستخدام الفعلي. بدء عملية التقييم في مرحلة مبكرة يضمن أن تستند قرارات التصميم إلى المخاوف المتعلقة بالأمان. في المقابل، يُعدّ منح التصاريح استنادًا إلى عمليات الرفض المرصودة فقط منهجًا غير آمن. استخدِم هذا الوقت لإجراء تدقيق أمني للجهاز وتسجيل الأخطاء المتعلّقة بالسلوك الذي لا يجب السماح به.
إزالة السياسة الحالية أو حذفها
هناك عدد من الأسباب الجيدة لإنشاء سياسة خاصة بالجهاز من الصفر على جهاز جديد، بما في ذلك:
- تدقيق الأمان
- سياسة متساهلة للغاية
- تقليل حجم السياسة
- سياسة فارغة
معالجة حالات رفض الخدمات الأساسية
يتم عادةً التعامل مع عمليات الرفض التي تنشئها الخدمات الأساسية من خلال تصنيف الملفات. مثلاً:
avc: denied { open } for pid=1003 comm=”mediaserver” path="/dev/kgsl-3d0” dev="tmpfs" scontext=u:r:mediaserver:s0 tcontext=u:object_r:device:s0 tclass=chr_file permissive=1 avc: denied { read write } for pid=1003 name="kgsl-3d0" dev="tmpfs" scontext=u:r:mediaserver:s0 tcontext=u:object_r:device:s0 tclass=chr_file permissive=1
تم حلّها بالكامل من خلال تصنيف /dev/kgsl-3d0
بشكل صحيح. في
هذا المثال، tcontext
هو device
. يمثّل ذلك
سياقًا تلقائيًا يتلقّى فيه كلّ شيء في /dev
التصنيف
"
device" ما لم يتمّ تحديد تصنيف أكثر تحديدًا. سيؤدي قبول
النتيجة من
audit2allow
هنا إلى إنشاء قاعدة غير صحيحة ومتساهلة للغاية.
لحلّ هذا النوع من المشاكل، امنح الملف تصنيفًا أكثر تحديدًا، وهو في هذه الحالة هو gpu_device. لا يلزم الحصول على أذونات إضافية لأنّه يمتلك mediaserver الأذونات اللازمة في السياسة الأساسية للوصول إلى gpu_device.
الملفات الأخرى الخاصة بالأجهزة والتي يجب تصنيفها بأنواع محدّدة مسبقًا في السياسة الأساسية:
- حظر الأجهزة
- الأجهزة الصوتية
- أجهزة الفيديو
- أجهزة الاستشعار
- nfc
- gps_device
- الملفات في /sys
- الملفات في /proc
بشكل عام، من الخطأ منح الأذونات للتصنيفات التلقائية. لا يُسمح بالعديد من هذه الأذونات بموجب قواعد neverallow، ولكن حتى في حال عدم عدم السماح بها صراحةً، من أفضل الممارسات توفير تصنيف محدّد.
تصنيف الخدمات الجديدة ومعالجة حالات الرفض
يجب تشغيل الخدمات التي يتم تشغيلها من خلال Init في نطاقات SELinux الخاصة بها. يضع المثال التالي الخدمة "foo" في نطاق SELinux الخاص بها ويمنحها أذونات.
يتم تشغيل الخدمة في ملف
init.device.rc
على جهازنا على النحو التالي:
service foo /system/bin/foo class core
- أنشئ نطاقًا جديدًا "foo"
أنشِئ الملف
device/manufacturer/device-name/sepolicy/foo.te
باستخدام المحتوى التالي:# foo service type foo, domain; type foo_exec, exec_type, file_type; init_daemon_domain(foo)
هذا هو النموذج الأولي لنطاق foo SELinux، والذي يمكنك إضافة قواعد إليه استنادًا إلى العمليات المحدّدة التي ينفّذها هذا الملف القابل للتنفيذ.
- التصنيف
/system/bin/foo
أضِف ما يلي إلى
device/manufacturer/device-name/sepolicy/file_contexts
:/system/bin/foo u:object_r:foo_exec:s0
يضمن ذلك تصنيف الملف القابل للتنفيذ بشكلٍ صحيح حتى يعمل SELinux على تنفيذ الخدمة في النطاق المناسب.
- إنشاء صور التشغيل والنظام وفلاشها
- يمكنك تحسين قواعد SELinux للنطاق.
استخدِم عمليات الرفض لتحديد الأذونات المطلوبة. تقدّم أداة audit2allow إرشادات جيدة، ولكن لا تستخدِمها إلا لتوجيه عملية penned لا تقتصر على نسخ الإخراج.
التبديل مرة أخرى إلى وضع التنفيذ
لا بأس بتحديد المشاكل وحلّها في الوضع المتساهل، ولكن عليك العودة إلى وضع التنفيذ في أقرب وقت ممكن ومحاولة البقاء فيه.
أخطاء شائعة
في ما يلي بعض الحلول للأخطاء الشائعة التي تحدث عند كتابة السياسات المتعلّقة بالأجهزة.
الاستخدام المفرط للنفي
يشبه مثال القاعدة التالي قفل الباب الأمامي مع ترك النوافذ مفتوحة:
allow { domain -untrusted_app } scary_debug_device:chr_file rw_file_perms
القصد واضح: يمكن للجميع الوصول إلى جهاز debugging ، باستثناء التطبيقات التابعة لجهات خارجية.
هناك عيوب في القاعدة لعدة أسباب. إنّ استبعاد untrusted_app
سهل التحايل عليه لأنّ جميع التطبيقات يمكنها تشغيل الخدمات في نطاق
isolated_app
اختياريًا. وبالمثل، إذا تمت إضافة نطاقات جديدة للتطبيقات التابعة لجهات خارجية
إلى AOSP، يمكنها أيضًا الوصول إلى scary_debug_device
.
القاعدة شديدة التساهل. لن تستفيد معظم النطاقات من استخدام
أداة تصحيح الأخطاء هذه. كان من المفترض أن يتم كتابة القاعدة للسماح فقط
بالنطاقات التي تتطلّب الوصول.
ميزات تصحيح الأخطاء في مرحلة الإنتاج
يجب ألا تكون ميزات تصحيح الأخطاء متوفّرة في إصدارات الإصدارات العلنية، كما يجب ألا تكون سياستها كذلك.
أبسط بديل هو السماح بميزة تصحيح الأخطاء فقط عند إيقاف ملف SELinux
في عمليات إنشاء eng/userdebug، مثل adb root
و
adb shell setenforce 0
.
من بين الخيارات البديلة الآمنة الأخرى تضمين أذونات تصحيح الأخطاء في عبارة userdebug_or_eng.
زيادة حجم السياسات بشكل كبير
يصف مقالة Characterizing SEAndroid Policies in the Wild اتجاهًا مقلقًا في زيادة عمليات تخصيص سياسة الجهاز. يجب أن تشكّل السياسة الخاصة بالجهاز نسبة تتراوح بين %5 و%10 من السياسة العامة التي يتم تنفيذها على الجهاز. من المؤكد تقريبًا أنّ عمليات التخصيص التي تزيد نسبتها عن%20 تتضمّن نطاقات مفوَّضة بشكل مفرط وسياسة غير سارية.
سياسة كبيرة جدًا بلا داعٍ:
- تؤثر بشكلٍ مزدوج في الذاكرة لأنّ السياسة موجودة في ذاكرة الوصول العشوائي ويتم تحميلها أيضًا في ذاكرة النواة.
- تؤدي إلى إهدار مساحة القرص من خلال الحاجة إلى صورة تمهيد أكبر.
- يؤثّر في أوقات البحث عن سياسة وقت التشغيل.
يوضّح المثال التالي جهازَين تبلغ فيها نسبة السياسة الخاصة بجهة التصنيع% 50 و% 40 من السياسة على الجهاز. أدّت إعادة صياغة السياسة إلى إجراء تحسينات كبيرة على الأمان بدون فقدان أي وظائف، كما هو موضح أدناه. (تم تضمين جهازَي AOSP Shamu وFlounder للمقارنة).
الشكل 1: مقارنة بين حجم السياسة الخاصة بالجهاز بعد تدقيق الأمان
وفي كلتا الحالتَين، تم تقليل حجم السياسة بشكل كبير وعدد
الأذونات. يرجع الانخفاض في حجم السياسة بالكامل تقريبًا إلى إزالة
الأذونات غير الضرورية، التي يُحتمل أن يكون الكثير منها قواعد أنشأها
audit2allow
وأُضيفت إلى السياسة بشكل عشوائي. كانت عناوين المواقع التي لم تعُد نشطة
سببًا في حدوث مشكلة في كلا الجهازَين.
منح إمكانية dac_override
يعني رفض dac_override
أنّ العملية المسيئة تحاول
الوصول إلى ملف باستخدام أذونات المستخدم/المجموعة/الجميع غير الصحيحة في نظام التشغيل Unix.
لا يُعدّ منح الإذن dac_override
هو الحلّ المناسب في أغلب الأحيان.
بدلاً من ذلك، يمكنك
تغيير أذونات Unix على الملف أو العملية. تحتاج بعض النطاقات، مثل
init
وvold
وinstalld
، إلى
القدرة على إلغاء أذونات ملفات نظام التشغيل Unix للوصول إلى ملفات العمليات الأخرى.
يمكنك الاطّلاع على مدوّنة "دان والش"
لمزيد من الشرح التفصيلي.