كتابة سياسة SELinux

يوفر مشروع Android مفتوح المصدر (AOSP) سياسة أساسية صلبة للتطبيقات والخدمات المشتركة عبر جميع أجهزة Android. يقوم المساهمون في AOSP بتحسين هذه السياسة بانتظام. من المتوقع أن تشكل السياسة الأساسية حوالي 90-95% من السياسة النهائية على الجهاز مع التخصيصات الخاصة بالجهاز التي تشكل نسبة 5-10% المتبقية. تركز هذه المقالة على هذه التخصيصات الخاصة بالجهاز، وكيفية كتابة سياسة خاصة بالجهاز، وبعض المخاطر التي يجب تجنبها على طول الطريق.

إحضار الجهاز

أثناء كتابة سياسة خاصة بالجهاز، اتبع الخطوات التالية.

تشغيل في وضع متساهل

عندما يكون الجهاز في وضع السماح ، يتم تسجيل حالات الرفض ولكن لا يتم فرضها. الوضع المسموح مهم لسببين:

  • يضمن الوضع المسموح ألا يؤدي عرض السياسة إلى تأخير مهام إظهار الجهاز المبكرة الأخرى.
  • قد يؤدي الرفض القسري إلى إخفاء حالات رفض أخرى. على سبيل المثال، يستلزم الوصول إلى الملفات عادةً البحث في الدليل، ثم فتح الملف، ثم قراءة الملف. في وضع الفرض، سيتم رفض بحث الدليل فقط. يضمن الوضع المسموح رؤية جميع حالات الرفض.

إن أبسط طريقة لوضع الجهاز في الوضع المسموح به هي استخدام سطر أوامر 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 علامة " الجهاز " ما لم يتم تعيين تسمية أكثر تحديدًا. إن مجرد قبول الإخراج من Audit2allow هنا قد يؤدي إلى قاعدة غير صحيحة ومتسامحة بشكل مفرط.

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

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

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

قم بتسمية الخدمات الجديدة ورفض العناوين

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

يتم إطلاق الخدمة في init. device .rc ملف 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 إرشادات جيدة، ولكنها تستخدم فقط لتوجيه عملية كتابة السياسات. لا تقم فقط بنسخ الإخراج.

قم بالتبديل مرة أخرى إلى وضع الفرض

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

الأخطاء الشائعة

فيما يلي بعض الحلول للأخطاء الشائعة التي تحدث عند كتابة السياسات الخاصة بالجهاز.

الإفراط في استخدام النفي

القاعدة النموذجية التالية تشبه قفل الباب الأمامي مع ترك النوافذ مفتوحة:

allow { domain -untrusted_app } scary_debug_device:chr_file rw_file_perms

القصد واضح: يمكن للجميع باستثناء تطبيقات الطرف الثالث الوصول إلى جهاز تصحيح الأخطاء.

القاعدة معيبة بعدة طرق. يعد استبعاد untrusted_app أمرًا بسيطًا للتغلب عليه نظرًا لأن جميع التطبيقات قد تقوم بشكل اختياري بتشغيل الخدمات في المجال isolated_app . وبالمثل، إذا تمت إضافة نطاقات جديدة لتطبيقات الجهات الخارجية إلى AOSP، فسيكون لها أيضًا إمكانية الوصول إلى scary_debug_device . القاعدة متساهلة بشكل مفرط. لن تستفيد معظم المجالات من الوصول إلى أداة تصحيح الأخطاء هذه. يجب أن تتم كتابة القاعدة للسماح فقط بالمجالات التي تتطلب الوصول.

ميزات التصحيح في الإنتاج

لا ينبغي أن تكون ميزات تصحيح الأخطاء موجودة في إصدارات الإنتاج ولا يجب أن تكون سياستها كذلك.

أبسط بديل هو السماح بميزة التصحيح فقط عند تعطيل SELinux على إصدارات eng/userdebug، مثل adb root و adb shell setenforce 0 .

البديل الآمن الآخر هو تضمين أذونات تصحيح الأخطاء في عبارة userdebug_or_eng .

انفجار حجم السياسة

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

سياسة كبيرة بلا داع:

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

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

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

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

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

منح القدرة dac_override

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