كتابة سياسة SELinux

يقدّم "المشروع المفتوح المصدر لنظام 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. ولا يلزم الحصول على مزيد من الأذونات لأنّ خادم الوسائط لديه الأذونات اللازمة حاليًا في السياسة الأساسية للوصول إلى gpu_device.

الملفات الأخرى الخاصة بالأجهزة والتي يجب تصنيفها بأنواع محدّدة مسبقًا في السياسة الأساسية:

بشكل عام، إنّ منح الأذونات للتصنيفات التلقائية ليس صحيحًا. لا يُسمح بالعديد من هذه الأذونات من خلال قواعد neverallow، ولكن حتى في حال عدم عدم السماح بها صراحةً، من أفضل الممارسات توفير تصنيف محدّد.

تصنيف الخدمات الجديدة وعمليات رفض العناوين

يجب أن يتم تشغيل الخدمات التي يتم إطلاقها في نطاقات SELinux الخاصة بها. يضع المثال التالي الخدمة "foo" في نطاق SELinux الخاص بها ويمنحها أذونات.

يتم إطلاق الخدمة في ملف init.device.rc الخاص بأجهزتنا على النحو التالي:

service foo /system/bin/foo
    class core
  1. إنشاء نطاق جديد "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، والذي يمكنك إضافة قواعد إليه استنادًا إلى العمليات المحدّدة التي ينفّذها هذا الملف القابل للتنفيذ.

  2. التصنيف /system/bin/foo

    أضِف ما يلي إلى device/manufacturer/device-name/sepolicy/file_contexts:

    /system/bin/foo   u:object_r:foo_exec:s0
    

    يضمن ذلك تصنيف الملف القابل للتنفيذ بشكل صحيح حتى يعمل SELinux على تنفيذ الخدمة في النطاق المناسب.

  3. إنشاء صور التمهيد والنظام وفلاشها
  4. يمكنك تحسين قواعد 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.

زيادة حجم السياسات بشكل كبير

يصف تصنيف سياسات SEAndroid في العالم توجّهًا مثيرًا للقلق في نمو عمليات تخصيص سياسات الأجهزة. يجب أن تشكّل السياسة الخاصة بالجهاز نسبة تتراوح بين %5 و%10 من السياسة العامة التي يتم تنفيذها على الجهاز. من المؤكد تقريبًا أنّ عمليات التخصيص التي تزيد نسبتها عن ‎20%تتضمّن نطاقات مفوَّضة بشكل مفرط وسياسة غير سارية.

سياسة كبيرة جدًا بلا داعٍ:

  • تؤثر بشكلٍ مزدوج في الذاكرة لأنّ السياسة موجودة في ذاكرة الوصول العشوائي ويتم تحميلها أيضًا في ذاكرة النواة.
  • تؤدي إلى إهدار مساحة القرص من خلال الحاجة إلى صورة تمهيد أكبر.
  • يؤثّر ذلك في أوقات البحث عن سياسة وقت التشغيل.

يوضّح المثال التالي جهازَين تبلغ فيها نسبة السياسة الخاصة بجهة التصنيع% 50 و% 40 من السياسة على الجهاز. أدّت إعادة صياغة السياسة إلى إجراء تحسينات كبيرة على الأمان بدون فقدان أي وظائف، كما هو موضح أدناه. (تم تضمين جهازَي AOSP Shamu وFlounder للمقارنة).

الشكل 1: مقارنة بين حجم السياسة الخاصة بالجهاز بعد تدقيق الأمان.

الشكل 1. مقارنة بين حجم السياسة الخاصة بالجهاز بعد تدقيق الأمان

وفي كلتا الحالتَين، تم تقليل حجم السياسة بشكل كبير وعدد الأذونات. يرجع الانخفاض في حجم السياسة بالكامل تقريبًا إلى إزالة الأذونات غير الضرورية، التي يُحتمل أن يكون الكثير منها قواعد أنشأها audit2allow وأُضيفت إلى السياسة بشكل عشوائي. كانت النطاقات المعطلة أيضًا مشكلة لكلا الجهازين.

منح إمكانية dac_override

يعني رفض dac_override أنّ العملية المسيئة تحاول الوصول إلى ملف باستخدام أذونات المستخدم/المجموعة/الجميع غير الصحيحة في نظام التشغيل Unix. لا يُعدّ منح الإذن dac_override هو الحلّ المناسب في أغلب الأحيان. بدلاً من ذلك، يمكنك تغيير أذونات Unix على الملف أو العملية. تحتاج بعض النطاقات، مثل init وvold وinstalld، إلى إمكانية إلغاء أذونات ملفات نظام التشغيل Unix للوصول إلى ملفات العمليات الأخرى. يمكنك الاطّلاع على مدوّنة "دان والش" لمزيد من التفاصيل.