توافق السياسة

توضِّح هذه المقالة كيفية تعامل نظام التشغيل Android مع مشاكل التوافق مع السياسة في عمليات التحديث عبر الهواء للنظام الأساسي، حيث قد تختلف إعدادات SELinux الجديدة للنظام الأساسي عن إعدادات SELinux القديمة الخاصة بالمورّد.

يراعي تصميم سياسة SELinux المستندة إلى Treble التمييز الثنائي بين سياسة النظام الأساسي وسياسة المورّد، ويصبح المخطّط أكثر تعقيدًا إذا كانت أقسام المورّد تُنشئ تبعيات، مثل platform < vendor < oem.

في الإصدار 8.0 من نظام التشغيل Android والإصدارات الأحدث، يتم تقسيم السياسة العامة لنظام SELinux إلى مكوّنات خاصة ومكوّنات عامة. تتألف المكوّنات المتاحة للجميع من السياسة والبنية الأساسية المرتبطة بها، والتي نضمن توفّرها لإصدار المنصة. ستظهر هذه السياسة لكاتبي سياسات المورّدين لتمكينهم من إنشاء ملف سياسة مورّد، والذي يؤدي عند دمجه مع السياسة المقدَّمة من النظام الأساسي إلى إنشاء سياسة تعمل بشكل كامل على الجهاز.

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

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

ملكية العناصر وتصنيفها

عند تخصيص السياسة في Android 8.0 والإصدارات الأحدث، يجب تحديد الملكية بوضوح لكل عنصر من أجل فصل سياسة المنصة عن سياسة المورّد. على سبيل المثال، إذا كان يصنِّف المورّد /dev/foo ثم تصنِّف المنصة /dev/foo في عملية OTA لاحقة، سيحدث سلوك غير محدّد. بالنسبة إلى SELinux، يظهر ذلك على شكل تعارض في التصنيف. يمكن أن تحتوي عقدة الجهاز على تصنيف واحد فقط يُحدّد التصنيف الذي تم تطبيقه أخيرًا. نتيجة لذلك:

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

يمكن أن تؤدي خصائص النظام أيضًا إلى حدوث تعارضات في الأسماء قد تؤدي إلى سلوك غير محدّد في النظام (بالإضافة إلى تصنيف SELinux). يمكن أن تحدث تداخلات بين تصنيفات النظام الأساسي والمورّد لأي عنصر يتضمّن تصنيفًا لنظام التشغيل SELinux ، بما في ذلك المواقع والخدمات والعمليات والملفات والمنافذ. لتجنُّب هذه المشاكل، حدِّد ملكية هذه العناصر بوضوح.

بالإضافة إلى تعارض التصنيفات، قد تتعارض أيضًا أسماء أنواع/سمات SELinux. سيؤدي تعارض اسم النوع/السمة دائمًا إلى خطأ في مُجمِّع السياسات.

مساحة أسماء النوع/السمة

لا يسمح SELinux بإعلانات متعددة للنوع أو السمة نفسها. لن يتمّ تجميع السياسة التي تحتوي على بيانات مكرّرة. لتجنُّب حدوث تعارضات في أسماء الأنواع والسمات، يجب أن تكون جميع بيانات المورّدين مُحدَّدة النطاق بدءًا من vendor_.

type foo, domain;  type vendor_foo, domain;

ملكية تصنيف العمليات وخصائص النظام

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

نوع الموقع البادئات المقبولة
التحكّم في الخصائص ctl.vendor.
ctl.start$vendor.
ctl.stop$vendor.
init.svc.vendor.
read-writable vendor.
للقراءة فقط ro.vendor.
ro.boot.
ro.hardware.
دائمة persist.vendor.

يمكن للمورّدين مواصلة استخدام ro.boot.* (التي تأتي من kernel cmdline) وro.hardware.* (وهي سمة واضحة مرتبطة بالأجهزة).

يجب أن تحتوي جميع خدمات المورّدين في ملفات init rc على vendor. للخدمات في ملفات init rc الخاصة بالأقسام غير النظامية. تُطبَّق قواعد مشابهة على تصنيفات SELinux لمواقع المورّدين (vendor_ لمواقع المورّدين).

ملكية الملف

يشكّل منع تعارض الملفات تحديًا لأنّ سياسة كل من المنصة والمورّد توفّر عادةً تصنيفات لجميع أنظمة الملفات. على عكس تسمية الأنواع، لا يكون وضع مساحة اسم للملفات عمليًا لأنّه يتم إنشاء العديد منها من قِبل النواة. لمنع حدوث هذه التعارضات، اتّبِع إرشادات التسمية لأنظمة الملفات في هذا القسم. بالنسبة إلى نظام Android 8.0، هذه اقتراحات بدون تنفيذ فني. في المستقبل، سيتم فرض هذه الاقتراحات من خلال مجموعة اختبار المورّد (VTS).

النظام (‎/system)

يجب أن تقدّم صورة النظام فقط تصنيفات لمكوّنات /system من خلال file_contexts وservice_contexts وما إلى ذلك. في حال إضافة تصنيفات لمكوّنات /system في سياسة /vendor، قد لا يكون تحديث OTA للإطار فقط ممكنًا.

المورّد (/vendor)

تُصنِّف سياسة SELinux في AOSP حاليًا أجزاء من vendorالتقسيم التي تتفاعل معها المنصة، ما يتيح كتابة قواعد SELinux لعمليات المنصة كي تتمكّن من التواصل و/أو الوصول إلى أجزاء من vendorالتقسيم. أمثلة:

مسار /vendor التصنيف المقدَّم من المنصة عمليات النظام الأساسي حسب التصنيف
/vendor(/.*)? vendor_file جميع عملاء HAL في إطار العمل وueventd وما إلى ذلك
/vendor/framework(/.*)? vendor_framework_file dex2oat وappdomain وما إلى ذلك
/vendor/app(/.*)? vendor_app_file dex2oat وinstalld وidmap وما إلى ذلك
/vendor/overlay(/.*) vendor_overlay_file system_server وzygote وidmap وما إلى ذلك

نتيجةً لذلك، يجب اتّباع قواعد محدّدة (يتم فرضها من خلال neverallows) عند تصنيف ملفات إضافية في القسم vendor:

  • يجب أن يكون vendor_file هو التصنيف التلقائي لجميع الملفات في القسم vendor. تتطلّب سياسة المنصة ذلك للوصول إلى عمليات تنفيذ HAL للمرور.
  • يجب أن تحتوي جميع exec_types الجديدة التي تمت إضافتها إلى قسم vendor من خلال سياسة SEPolicy الخاصة بالمورّد على سمة vendor_file_type. يتم فرض ذلك من خلال neverallows.
  • لتجنُّب حدوث تعارضات مع تحديثات المنصة أو الإطار في المستقبل، تجنَّب تصنيف ملفات غير exec_types في قسم vendor.
  • يجب أن تكون جميع متطلّبات المكتبة لواجهة برمجة التطبيقات (HAL) لعملية AOSP نفسها التي تم تحديدها في AOSP مُصنَّفة على أنّها same_process_hal_file..

Procfs (‎/proc)

يمكن تصنيف الملفات في /proc باستخدام تصنيف genfscon فقط. في Android 7.0، كانت كل من سياسة النظام الأساسي وسياسة المورّد تستخدِم genfscon لتصنيف الملفات في procfs.

اقتراح: تصنيفات سياسات المنصة فقط /proc. إذا كانت عمليات vendor تحتاج إلى الوصول إلى الملفات في /proc التي تم تصنيفها حاليًا باستخدام التصنيف التلقائي (proc)، يجب ألا تحدّد سياسة المورّد تصنيفًا صريحًا لها، بل يجب استخدام النوع العام proc بدلاً من ذلك لإضافة قواعد لنطاقات المورّدين. يتيح ذلك لتعديلات المنصة acomodate واجهات kernel المستقبلية التي يتم عرضها من خلال procfs وتصنيفها بوضوح حسب الحاجة.

Debugfs (‎/sys/kernel/debug)

يمكن تصنيف Debugfs في كل من file_contexts و genfscon. في الإصدارات من Android 7.0 إلى Android 10، يتم استخدام تصنيف كل من النظام الأساسي والمورّد debugfs.

في Android 11، لا يمكن الوصول إلى debugfs أو تثبيته على الأجهزة العلنية. على الشركات المصنّعة للأجهزة إزالة debugfs.

Tracefs (‎/sys/kernel/debug/tracing)

يمكن تصنيف Tracefs في كل من file_contexts و genfscon. في Android 7.0، تظهر تصنيفات المنصة فقط tracefs.

اقتراح: يمكن فقط للمنصة تصنيف tracefs.

Sysfs (‎/sys)

يمكن تصنيف الملفات في /sys باستخدام كل من file_contexts وgenfscon. في Android 7.0، يستخدم كلّ من النظام الأساسي والمورّد genfscon لتصنيف الملفات في sysfs.

اقتراح: قد تصنّف المنصة sysfs العقد التي لا تكون خاصة بالأجهزة. بخلاف ذلك، يمكن فقط للمورّد تصنيف الملفات.

tmpfs (/dev)

قد يتم تصنيف الملفات في /dev ضمن file_contexts. في Android 7.0، يمكنك العثور على ملفَي تصنيف النظام الأساسي والمورّد هنا.

اقتراح: يمكن أن يصنّف المورّد الملفات فقط في /dev/vendor (على سبيل المثال، /dev/vendor/foo، /dev/vendor/socket/bar).

Rootfs (‎/)

قد يتم تصنيف الملفات في / ضمن file_contexts. في الإصدار 7.0 من نظام التشغيل Android، يمكنك العثور على كل من ملفات تصنيف المورّد والمنصة هنا.

اقتراح: يمكن للنظام فقط تصنيف الملفات في /.

البيانات (‎/data)

يتم تصنيف البيانات من خلال تركيبة من file_contexts و seapp_contexts.

اقتراح: لا تسمح بتصنيف المورّد خارج /data/vendor. يمكن للمنصة فقط تصنيف الأجزاء الأخرى من /data.

إصدار تصنيفات Genfs

اعتبارًا من المستوى 202504 لواجهة برمجة التطبيقات الخاصة بالمطوّر، تكون تصنيفات SELinux الأحدث التي تم تعيينها باستخدام genfscon في system/sepolicy/compat/plat_sepolicy_genfs_{ver}.cil اختيارية لأقسام المطوّر القديمة. يتيح ذلك لأقسام المورّدين القديمة الاحتفاظ بتنفيذ SEPolicy الحالي. يتم التحكّم في هذا الإعداد من خلال المتغيّر BOARD_GENFS_LABELS_VERSION في Makefile والذي يتم تخزينه في /vendor/etc/selinux/genfs_labels_version.txt.

مثال:

  • في مستوى واجهة برمجة التطبيقات الخاص بالمورّد 202404، يتم تصنيف عقدة /sys/class/udc على أنّها sysfs تلقائيًا.
  • اعتبارًا من مستوى واجهة برمجة التطبيقات 202504 لدى المورّد، يتم تصنيف /sys/class/udc على أنّه sysfs_udc.

ومع ذلك، قد تكون /sys/class/udc قيد الاستخدام من قِبل أقسام المورّدين التي تستخدم مستوى واجهة برمجة التطبيقات 202404، إما باستخدام التصنيف التلقائي sysfs أو تصنيف خاص بالمورّد. قد يؤدي وضع تصنيف /sys/class/udc على sysfs_udc بدون قيد أو شرط إلى إيقاف التوافق مع أقسام المورّدين هذه. من خلال وضع علامة في المربّع BOARD_GENFS_LABELS_VERSION، تستمر المنصة في استخدام التصنيفات والأذونات السابقة لأقسام المورّدين القديمة.

يمكن أن يكون BOARD_GENFS_LABELS_VERSION أكبر من أو يساوي مستوى واجهة برمجة التطبيقات الخاصة بالمورّد. على سبيل المثال، يمكن أن تضبط أقسام المورّدين التي تستخدم المستوى 202404 من واجهة برمجة التطبيقات القيمة BOARD_GENFS_LABELS_VERSION على 202504 لاعتماد التصنيفات الجديدة التي تم تقديمها في 202504. اطّلِع على قائمة تصنيفات genfs الخاصة بـ 202504.

عند تصنيف عقد genfscon، يجب أن تأخذ المنصة في الاعتبار أقسام المورّدين القديمة وتطبّق آليات النسخ الاحتياطي للتوافق عند الحاجة. يمكن أن تستخدم المنصة مكتبات مخصّصة للمنصة فقط لطلب معلومات عن إصدار تصنيفات genfs.

سمات التوافق

سياسة SELinux هي تفاعل بين نوعَي المصدر والهدف لفئَين محدّدتَين من فئات الكائنات والأذونات. قد يكون لكل عنصر (عمليات وملفات وما إلى ذلك) متأثر بسياسة SELinux نوع واحد فقط، ولكن قد يكون لهذا النوع سمات متعدّدة.

تم صياغة السياسة بشكل أساسي من حيث الأنواع الحالية:

allow source_type target_type:target_class permission(s);

ويعود ذلك إلى أنّ السياسة قد تمّ إعدادها مع الأخذ في الاعتبار جميع الأنواع. ومع ذلك، إذا كانت سياسة المورّد وسياسة المنصة تستخدمان أنواعًا معيّنة، وتغيّر تصنيف عنصر معيّن في إحدى هاتين السياستَين فقط، قد تحتوي السياسة الأخرى على سياسة اكتسبت إذن الوصول أو فقدته في السابق. مثلاً:

File_contexts:
/sys/A   u:object_r:sysfs:s0
Platform: allow p_domain sysfs:class perm;
Vendor: allow v_domain sysfs:class perm;

يمكن تغييرها إلى:

File_contexts:
/sys/A   u:object_r:sysfs_A:s0

على الرغم من أنّ سياسة المورّد ستظلّ كما هي، سيفقد v_domain إذن الوصول بسبب عدم توفّر سياسة لنوع sysfs_A الجديد.

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

إنّ تحديد السياسة العامة كسمات لها إصدارات يحقق هدفين متعلّقين بالتوافق مع السياسة:

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

إمكانية كتابة السياسات

لتحقيق هدف عدم الحاجة إلى معرفة تغييرات إصدار معيّنة لأجل تطوير السياسات، يتضمّن الإصدار 8.0 من Android تعيينًا بين أنواع السياسات المتاحة للجميع على النظام الأساسي والسمات الخاصة بها. تمّ ربط النوع foo بالسمة foo_vN، حيث يكون N هو الإصدار المستهدَف. يتوافق العنصر vN مع متغيّر الإنشاء PLATFORM_SEPOLICY_VERSION وهو من النوع MM.NN، حيث يتوافق MM مع رقم حزمة SDK الخاصة بالنظام الأساسي وNN هو إصدار خاص بسياسات الأمان على النظام الأساسي.

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

يتم تضمين السياسة العامة للمنصة التي تم تصديرها بتنسيق allow source_foo target_bar:class perm; كجزء من سياسة المورّد. أثناء عملية التجميع (التي تتضمّن الإصدار المقابل)، يتم تحويلها إلى السياسة التي ستنتقل إلى جزء المورّد من الجهاز (المعروض في لغة CIL المُحوَّلة):

 (allow source_foo_vN target_bar_vN (class (perm)))

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

الاختلافات في السياسات

لا يؤدي إنشاء السمات تلقائيًا عن طريق إضافة _vN إلى نهاية كل نوع إلى أيّ إجراء بدون ربط السمات بالأنواع في اختلافات الإصدارات. يحتفظ نظام التشغيل Android بربط بين إصدارات السمات و ربط الأنواع بهذه السمات. ويتم ذلك في ملفات الربط المذكورة أعلاه باستخدام عبارات، مثل (CIL):

(typeattributeset foo_vN (foo))

ترقيات المنصة

يوضّح القسم التالي سيناريوهات ترقيات المنصة.

الأنواع نفسها

يحدث هذا السيناريو عندما لا يغيّر عنصر التصنيفات في إصدارات السياسة. وينطبق ذلك على نوعَي المصدر والهدف ويمكن الاطّلاع عليه باستخدام /dev/binder، الذي يحمل التصنيف binder_device في جميع الإصدارات. يتم تمثيلها في السياسة المحوَّلة على النحو التالي:

binder_device_v1 … binder_device_vN

عند الترقية من v1 إلى v2، يجب أن تتضمن سياسة المنصة ما يلي:

type binder_device; -> (type binder_device) (in CIL)

في ملف الربط بالإصدار 1 (CIL):

(typeattributeset binder_device_v1 (binder_device))

في ملف الربط بالإصدار 2 (CIL):

(typeattributeset binder_device_v2 (binder_device))

في سياسة المورّد من الإصدار 1 (CIL):

(typeattribute binder_device_v1)
(allow binder_device_v1 )

في سياسة المورّد من الإصدار 2 (CIL):

(typeattribute binder_device_v2)
(allow binder_device_v2 )
أنواع جديدة

يحدث هذا السيناريو عندما تضيف المنصة نوعًا جديدًا، ويمكن أن يحدث ذلك عند إضافة ميزات جديدة أو أثناء تشديد السياسة.

  • ميزة جديدة: عندما يصنّف النوع عنصرًا لم يكن موجودًا من قبل (مثل عملية خدمة جديدة)، لا يتفاعل رمز المورّد معه مباشرةً في السابق، لذا لا تتوفّر سياسة مقابلة. لا تحتوي السمة الجديدة التي تتوافق مع النوع على سمة في الإصدار السابق من الملف، وبالتالي لن تحتاج إلى إدخال في ملف الربط الذي يستهدف هذا الإصدار من الملف.
  • تعزيز السياسات: عندما يمثّل النوع تشديدًا للسياسة، يجب أن ترتبط سمة النوع الجديدة بسلسلة من السمات التي تتوافق مع السلسلة السابقة (على غرار المثال السابق الذي يغيّر /sys/A من sysfs إلى sysfs_A). يعتمد رمز المورّد على قاعدة تتيح الوصول إلى sysfs، ويجب أن يتضمّن هذه القاعدة كسمة للنوع الجديد.

عند الترقية من v1 إلى v2، يجب أن تتضمن سياسة المنصة ما يلي:

type sysfs_A; -> (type sysfs_A) (in CIL)
type sysfs; (type sysfs) (in CIL)

في ملف الربط بالإصدار 1 (CIL):

(typeattributeset sysfs_v1 (sysfs sysfs_A))

في ملف الربط بالإصدار 2 (CIL):

(typeattributeset sysfs_v2 (sysfs))
(typeattributeset sysfs_A_v2 (sysfs_A))

في سياسة المورّد من الإصدار 1 (CIL):

(typeattribute sysfs_v1)
(allow  sysfs_v1 )

في سياسة المورّد من الإصدار 2 (CIL):

(typeattribute sysfs_A_v2)
(allow  sysfs_A_v2 )
(typeattribute sysfs_v2)
(allow  sysfs_v2 )
الأنواع التي تمت إزالتها

يحدث هذا السيناريو (النادر) عند إزالة نوع، ويمكن أن يحدث ذلك عندما يكون العنصر الأساسي:

  • يبقى المحتوى معروضًا ولكن يتم تصنيفه بشكل مختلف.
  • تمت إزالته من قِبل المنصة

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

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

(typeattribute sysfs_v1)
(allow  sysfs_v1 )

المثال 1: تصغير الأنواع (إزالة sysfs_A)

عند الترقية من v1 إلى v2، يجب أن تتضمن سياسة المنصة ما يلي:

type sysfs; (type sysfs) (in CIL)

في ملف الربط بالإصدار 1 (CIL):

(typeattributeset sysfs_v1 (sysfs))
(type sysfs_A) # in case vendors used the sysfs_A label on objects
(typeattributeset sysfs_A_v1 (sysfs sysfs_A))

في ملف الربط بالإصدار 2 (CIL):

(typeattributeset sysfs_v2 (sysfs))

في سياسة المورّد من الإصدار 1 (CIL):

(typeattribute sysfs_A_v1)
(allow  sysfs_A_v1 )
(typeattribute sysfs_v1)
(allow  sysfs_v1 )

في سياسة المورّد من الإصدار 2 (CIL):

(typeattribute sysfs_v2)
(allow  sysfs_v2 )

المثال 2: الإزالة بالكامل (نوع foo)

عند الترقية من v1 إلى v2، يجب أن تتضمن سياسة المنصة ما يلي:

# nothing - we got rid of the type

في ملف الربط بالإصدار 1 (CIL):

(type foo) #needed in case vendors used the foo label on objects
(typeattributeset foo_v1 (foo))

في ملف الربط بالإصدار 2 (CIL):

# nothing - get rid of it

في سياسة المورّد من الإصدار 1 (CIL):

(typeattribute foo_v1)
(allow foo )
(typeattribute sysfs_v1)
(allow sysfs_v1 )

في سياسة المورّد من الإصدار 2 (CIL):

(typeattribute sysfs_v2)
(allow sysfs_v2 )
فئة/أذونات جديدة

يحدث هذا السيناريو عندما تُضيف ترقية المنصة مكوّنات سياسة جديدة لم تكن متوفّرة في الإصدارات السابقة. على سبيل المثال، عندما أضاف نظام التشغيل Android أداة إدارة ملفّات servicemanager التي أنشأت أذونات الإضافة والبحث والعرض ، لم تحصل خدمات الجهاز التي تريد التسجيل في servicemanager على الأذونات التي كانت تحتاج إليها ولم تكن متوفرة. في الإصدار 8.0 من نظام التشغيل Android، لا يمكن إلا لسياسة المنصة إضافة فئات وأذونات جديدة.

للسماح لجميع النطاقات التي كان من الممكن إنشاؤها أو تمديدها بموجب سياسة المورّد باستخدام الفئة الجديدة بدون عائق، يجب أن تتضمّن سياسة المنصة قاعدة مشابهة لما يلي:

allow {domain -coredomain} *:new_class perm;

وقد يتطلّب ذلك أيضًا سياسة تسمح بالوصول إلى جميع أنواع الواجهات (السياسة العامة)، لضمان حصول صورة المورّد على إذن الوصول. إذا أدّى ذلك إلى عدم قبول سياسة الأمان (كما قد يحدث مع تغييرات servicemanager)، قد يتم فرض ترقية من المورّد.

الصف أو الأذونات التي تمت إزالتها

يحدث هذا السيناريو عند إزالة مدير كائن (مثل مدير كائن ZygoteConnection) ولا يُفترض أن يتسبب في حدوث مشاكل. يمكن أن تظل فئة "مدير الكائنات" وأذوناته محدّدة في السياسة إلى أن يتوقف "إصدار المورّد" عن استخدامها. ويتم ذلك من خلال إضافة التعريفات إلى ملف الربط المقابل.

تخصيص المورّد للأنواع الجديدة أو التي تمت إعادة تصنيفها

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

وبما أنّ سياسة المورّد هي دائمًا الأقدم على الجهاز، ما مِن حاجة إلى تحويل جميع أنواع المورّدين تلقائيًا إلى سمات في السياسة. لا تعتمد المنصة على أيّ شيء مصنّف في سياسة المورّد لأنّ المنصة ليس لديها معرفة بهذا النوع من التصنيفات. ومع ذلك، ستوفّر المنصة السمات والأنواع العامة التي تستخدمها للتفاعل مع العناصر المصنّفة بهذه الأنواع (مثل domain وsysfs_type وما إلى ذلك). لكي تستمر المنصة في التفاعل بشكل صحيح مع هذه العناصر، يجب تطبيق السمات والأنواع بشكل مناسب، وقد تحتاج إلى إضافة قواعد محدّدة إلى النطاقات القابلة للتخصيص (مثل init).

تغييرات السمات في Android 9

يمكن للأجهزة التي يتم ترقيتها إلى Android 9 استخدام السمات التالية، ولكن يجب ألا تستخدمها الأجهزة التي تبدأ بتشغيل Android 9.

سمات المخالف

يتضمّن نظام التشغيل Android 9 السمات التالية ذات الصلة بالنطاقات:

  • data_between_core_and_vendor_violators. سمة لجميع النطاقات التي تنتهك شرط عدم مشاركة الملفات من خلال مسار بين vendor وcoredomains. يجب ألا تستخدم عمليات النظام الأساسي وموفّري البرامج ملفات على القرص للتواصل (واجهة برمجة التطبيقات غير المستقرة). اقتراح:
    • يجب استخدام /data/vendor في رمز المورّد.
    • يجب ألا يستخدم النظام /data/vendor.
  • سمة system_executes_vendor_violators. لجميع نطاقات النظام (باستثناء init وshell domains) التي تنتهك شرط عدم تنفيذ ملفات ثنائية للمورّدين تنفيذ ملفّات ثنائية المصنّع لها واجهة برمجة تطبيقات غير مستقرة. يجب ألا تنفِّذ المنصة ملفّات الثنائيات الخاصة بالمورّد مباشرةً. اقتراح:
    • يجب أن تكون تبعيات النظام الأساسي هذه على ملفات ثنائية المصنّع متأخرة عن واجهات HIDL HAL.

      أو

    • يجب نقل coredomains التي تحتاج إلى الوصول إلى ملفات ثنائية المورّد إلى قسم المورّد، وبالتالي سيتوقف تطبيقك عن أن يكون coredomain.

السمات غير الموثوق بها

يجب ألا تحصل التطبيقات غير الموثوق بها التي تستضيف رمزًا عشوائيًا على إذن الوصول إلى خدمات HwBinder ، باستثناء الخدمات التي يُعتبَر أنّها آمنة بما يكفي للوصول إليها من هذه التطبيقات (راجِع الخدمات الآمنة أدناه). في ما يلي السببان الرئيسيان لذلك:

  1. لا تُجري خوادم HwBinder مصادقة العميل لأنّ HIDL لا تُظهر حاليًا معلومات UID للمتصل. حتى إذا كانت HIDL تعرض هذه البيانات، فإنّ العديد من خدمات HwBinder تعمل على مستوى أقل من مستوى التطبيقات (مثل واجهات HAL) أو يجب ألا تعتمد على هوية التطبيق للحصول على الإذن. وبالتالي، من أجل ضمان الأمان، فإنّ الافتراض التلقائي هو أنّ كل خدمة HwBinder تتعامل مع جميع عملائها على أنّهم مفوَّضون بالتساوي لتنفيذ العمليات التي تقدّمها الخدمة.
  2. تحتوي خوادم HAL (مجموعة فرعية من خدمات HwBinder) على رمز برمجي يتضمن معدلًا أعلى من حدوث مشاكل الأمان مقارنةً بمكونات system/core، ويمكنها الوصول إلى الطبقات السفلية من الحزمة (وصولاً إلى الأجهزة)، ما يؤدي بالتالي إلى زيادة فرص تجاوز نموذج أمان Android.

الخدمات الآمنة

تشمل الخدمات الآمنة ما يلي:

  • same_process_hwservice. يتم تشغيل هذه الخدمات (بحكم التعريف) في عملية العميل، وبالتالي يكون لها إذن الوصول نفسه الذي يتمتع به نطاق العميل الذي تتم فيه تنفيذ العملية.
  • coredomain_hwservice. لا تشكل هذه الخدمات أي مخاطر مرتبطة بالأسباب المذكورة في النقطة 2.
  • hal_configstore_ISurfaceFlingerConfigs. تم تصميم هذه الخدمة خصيصًا لاستخدامها من قِبل أي نطاق.
  • hal_graphics_allocator_hwservice. توفّر خدمة surfaceflinger Binder أيضًا هذه العمليات، ويُسمح للتطبيقات بالوصول إليها.
  • hal_omx_hwservice: هذا هو إصدار HwBinder من mediacodec خدمة Binder، والتي يُسمح للتطبيقات بالوصول إليها.
  • hal_codec2_hwservice. هذا إصدار أحدث من hal_omx_hwservice.

السمات القابلة للاستخدام

تحتوي جميع hwservices غير الآمنة على السمة untrusted_app_visible_hwservice. تحتوي خوادم HAL المقابلة على السمة untrusted_app_visible_halserver. يجب ألّا تستخدم الأجهزة التي تعمل بنظام التشغيل Android 9 أيًا من سمة untrusted.

اقتراح:

  • بدلاً من ذلك، يجب أن تتواصل التطبيقات غير الموثوق بها مع خدمة نظام تتواصل بدورها مع HAL HIDL الخاصة بالمورّد. على سبيل المثال، يمكن للتطبيقات التواصل مع binderservicedomain، ثم يتواصل mediaserver (وهو binderservicedomain) بدوره مع hal_graphics_allocator.

    أو

  • يجب أن يكون للتطبيقات التي تحتاج إلى الوصول المباشر إلى واجهات برمجة التطبيقات vendor HALs نطاق سياسات الأمان الخاص بها والذي يحدّده المورّد.

اختبارات سمات الملفات

يتضمّن Android 9 اختبارات وقت الإنشاء التي تضمن أن تتضمّن جميع الملفات في مواقع محددة السمات المناسبة (مثلاً، تتضمّن جميع الملفات في sysfs السمة المطلوبة sysfs_type).

السياسة العامة للمنصة

تشكّل السياسة العامة للمنصة جوهر الامتثال لنموذج بنية Android 8.0 بدون الحفاظ على اتحاد سياسات المنصة من الإصدار 1 والإصدار 2. يتعرّض المورّدون لمجموعة فرعية من سياسة المنصة التي تحتوي على أنواع وسمات وقواعد قابلة للاستخدام بشأن هذه الأنواع والسمات التي تصبح بعد ذلك جزءًا من سياسة المورّد (أي vendor_sepolicy.cil).

تتم ترجمة الأنواع والقواعد تلقائيًا في السياسة التي ينشئها المورّد إلى attribute_vN بحيث تكون جميع الأنواع التي تقدّمها المنصة سمات لها إصدارات (مع ذلك، لا يتم إصدار السمات). يتحمّل النظام الأساسي مسؤولية ربط الأنواع المحدّدة التي يوفّرها بالسمات المناسبة لضمان استمرار عمل سياسة المورّد وتضمين القواعد المتوفّرة لإصدار معيّن. إنّ الجمع بين السياسة العامة للمنصة وسياسة المورّد يلبّي هدف نموذج بنية Android 8.0 المتمثل في السماح بإنشاءات مستقلة للمنصة والمورّد.

الربط بسلاسل السمات

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

إنّ الحفاظ على هدف إخفاء معلومات الإصدار عن كاتب السياسة يعني إنشاء السمات التي تتضمّن معلومات الإصدار تلقائيًا وتخصيصها للأنواع الملائمة. في الحالة الشائعة للأنواع الثابتة، يكون هذا الأمر بسيطًا: يتم ربط type_foo بـ type_foo_v1.

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

الإصدارات السابقة

للتبسيط، يُطلق نظام Android الأساسي إصدارًا من سياسة الأمان عند إنشاء مسار إصدار جديد. كما هو موضّح أعلاه، يتضمّن PLATFORM_SEPOLICY_VERSION رقم الإصدار ويكون على الشكل MM.nn، ويشير MM إلى قيمة حزمة SDK وnn هي قيمة خاصة يتم الاحتفاظ بها في /platform/system/sepolicy.. على سبيل المثال، 19.0 لنظام التشغيل Kitkat و21.0 لنظام التشغيل Lollipop و22.0 لنظام التشغيل Lollipop-MR1 و23.0 لنظام التشغيل Marshmallow و24.0 لنظام التشغيل Nougat و25.0 لنظام التشغيل Nougat-MR1 و26.0 لنظام التشغيل Oreo و27.0 لنظام التشغيل Oreo-MR1 و28.0 لنظام التشغيل Android 9. لا تكون التحديثات دائمًا أعدادًا صحيحة. على سبيل المثال، إذا كان تحديث MR إلى إصدار معيّن يتطلّب إجراء تغيير غير متوافق في system/sepolicy/public ولكن ليس تحديث واجهة برمجة التطبيقات، يمكن أن يكون إصدار سياسة الأمان هذا: vN.1. الإصدار المتوفر في أحد مشاريع التطوير هو إصدار لا يتم استخدامه أبدًا في الأجهزة المُرسَلة 10000.0.

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

تأثير الأداء للسمات المتعدّدة

على النحو الموضّح في https://github.com/SELinuxProject/cil/issues/9، يؤدي تحديد عدد كبير من السمات لنوع معيّن إلى حدوث مشاكل في الأداء في حال عدم توفّر ذاكرة التخزين المؤقت للسياسة.

تم تأكيد أنّ هذه مشكلة في Android، لذا تم إجراء تغييرات على Android 8.0 لإزالة السمات التي أضافها compilador السياسة إلى السياسة، بالإضافة إلى إزالة السمات غير المستخدَمة. أدّت هذه التغييرات إلى حلّ مشكلات تدهور الأداء.

نظام_خارجي السياسة العامة للمنتجات والسياسة العامة

بدءًا من Android 11، يُسمح لقسمَي system_ext وproduct ب تصدير أنواعهما العامة المحدّدة إلى قسم المورّد. مثل سياسة العلن المتعلقة بالمنصة، يستخدم المورّد أنواعًا وقواعد يتم تحويلها تلقائيًا إلى السمات التي تتضمّن إصدارًا، على سبيل المثال، من type إلى type_N، حيث يكون N هو إصدار المنصة التي تم إنشاء قسم المورّد وفقًا لها.

عندما تستند القسمَين system_ext وproduct إلى إصدار النظام الأساسي نفسه N، ينشئ نظام الإنشاء ملفات ربط أساسية لملفَي system_ext/etc/selinux/mapping/N.cil و product/etc/selinux/mapping/N.cil، اللذَين يحتويان على عمليات ربط هوية من type إلى type_N. يمكن للمورّد الوصول إلى type باستخدام السمة التي تتضمّن إصدارًا type_N.

في حال تعديل قسمَي system_ext وproduct فقط، مثلاً من N إلى N+1 (أو إصدار أحدث)، بينما يبقى القسم المخصّص للمورّد على N، قد يفقد المورّد إمكانية الوصول إلى أنواع قسمَي system_ext وproduct. لمنع حدوث أي مشاكل، يجب أن توفّر أقسام system_ext وproduct ملفات ربط من الأنواع المحددة إلى سمات type_N. يكون كل شريك مسؤولاً عن صيانة ملفات الربط، إذا كان سيوفّر N للمورّد باستخدام N+1 (أو إصدار أحدث) system_ext وproduct.

ولإجراء ذلك، على الشركاء:

  1. انسخ ملفات الربط الأساسية التي تم إنشاؤها من قسمَي N system_ext وproduct إلى شجرة المصدر.
  2. عدِّل ملفات الربط حسب الحاجة.
  3. ثبِّت ملفّات الربط على قسمَي system_ext و product في N+1 (أو إصدار أحدث).

على سبيل المثال، لنفترض أنّ N system_ext يحتوي على نوع واحد علني يُسمى foo_type. بعد ذلك، سيظهر system_ext/etc/selinux/mapping/N.cil في القسم N system_ext على النحو التالي:

(typeattributeset foo_type_N (foo_type))
(expandtypeattribute foo_type_N true)
(typeattribute foo_type_N)

في حال إضافة bar_type إلى N+1 system_ext، وإذا كان يجب ربط bar_type بـ foo_type لأجل N المورّد، يمكن تعديل N.cil من

(typeattributeset foo_type_N (foo_type))

إلى

(typeattributeset foo_type_N (foo_type bar_type))

ثم تم تثبيته على قسم N+1 system_ext. يمكن لمورّد N مواصلة الوصول إلى foo_type وbar_type في N+1 system_ext.

تصنيف سياقات SELinux

لدعم التمييز بين سياسة أمان نظام التشغيل والمورّد، يُنشئ النظام ملفات سياق SELinux بشكلٍ مختلف لإبقائها منفصلة.

سياقات الملفات

أدخل نظام Android 8.0 التغييرات التالية على file_contexts:

  • لتجنُّب زيادة وقت الترجمة على الجهاز أثناء بدء التشغيل، file_contexts لن يعود متوفّرًا بالتنسيق الثنائي. بدلاً من ذلك، هي ملفات نصية قابلة للقراءة للتعبيرات العادية، مثل {property, service}_contexts (كما كانت في الإصدارات السابقة من 7.0).
  • يتم تقسيم file_contexts بين ملفين:
    • plat_file_contexts
      • نظام التشغيل Android file_context الذي لا يحتوي على علامات خاصة بالجهاز، باستثناء تصنيف أجزاء من القسم /vendor التي يجب تصنيفها بدقة لضمان العمل السليم لملفات sepolicy
      • يجب أن تكون مضمّنة في القسم system في العنوان /system/etc/selinux/plat_file_contexts على الجهاز ويحمّلها init في البداية مع المورّد file_context.
    • vendor_file_contexts
      • file_context خاص بالجهاز تم إنشاؤه من خلال دمج file_contexts المتوفّرة في الأدلة التي تشير إليها BOARD_SEPOLICY_DIRS في ملفات Boardconfig.mk على الجهاز
      • يجب تثبيته في ملف ‎/vendor/etc/selinux/vendor_file_contexts في القسم ‎vendor وتحميله بواسطة ‎init في ‎ البداية مع المنصة ‎file_context.

سياقات المواقع

في Android 8.0، يتم تقسيم property_contexts بين ملفين:

  • plat_property_contexts
    • نظام التشغيل Android property_context الذي لا يحتوي على تصنيفات خاصة بالأجهزة
    • يجب أن يكون مضمّنًا في القسم system في العنوان /system/etc/selinux/plat_property_contexts وأن يتم تحميله بواسطة init في البداية مع المورّد property_contexts.
  • vendor_property_contexts
    • property_context خاص بالجهاز تم إنشاؤه من خلال دمج property_contexts المتوفّرة في الأدلة التي تشير إليها BOARD_SEPOLICY_DIRS في ملفات Boardconfig.mk على الجهاز
    • يجب أن يكون مضمّنًا في القسم vendor في /vendor/etc/selinux/vendor_property_contexts وأن يتم carregarه من قِبل init في البداية مع النظام الأساسي property_context

سياقات الخدمة

في Android 8.0، يتم تقسيم service_contexts بينملفَين التاليين:

  • plat_service_contexts
    • service_context المخصّصة لنظام Android الأساسي servicemanager لا يحتوي service_context على تصنيفات خاصة بالأجهزة.
    • يجب أن يكون مضمّنًا في قسم system في العنوان /system/etc/selinux/plat_service_contexts وأن يتم تحميله بواسطة servicemanager في البداية مع المورّد service_contexts.
  • vendor_service_contexts
    • service_context خاص بالجهاز تم إنشاؤه من خلال دمج service_contexts المتوفّرة في الأدلة التي تشير إليها BOARD_SEPOLICY_DIRS في ملفات Boardconfig.mk على الجهاز
    • يجب أن يكون مضمّنًا في القسم vendor في /vendor/etc/selinux/vendor_service_contexts وأن يتم تحميله بواسطة servicemanager في البداية مع النظام الأساسي service_contexts.
    • على الرغم من أنّ servicemanager يبحث عن هذا الملف في وقت التشغيل، يجب ألّا يكون vendor_service_contexts متوفّرًا في جهاز TREBLE متوافق تمامًا. ويرجع ذلك إلى أنّه يجب أن يتم من خلال hwservicemanager/hwbinder كل التفاعل بين عمليةvendor وعمليةsystem.
  • plat_hwservice_contexts
    • نظام التشغيل Android hwservice_context لنظام التشغيل hwservicemanager الذي لا يتضمّن تصنيفات خاصة بالأجهزة
    • يجب أن تكون مضمّنة في القسم system في العنوان /system/etc/selinux/plat_hwservice_contexts وأن يتم تحميلها بواسطة hwservicemanager في البداية مع vendor_hwservice_contexts.
  • vendor_hwservice_contexts
    • hwservice_context خاص بالجهاز تم إنشاؤه من خلال دمج hwservice_contexts المتوفّرة في الأدلة التي تشير إليها BOARD_SEPOLICY_DIRS في ملفات Boardconfig.mk على الجهاز
    • يجب أن تكون مضمّنة في القسم vendor في العنوان /vendor/etc/selinux/vendor_hwservice_contexts وأن يتم carregarla من خلال hwservicemanager في البداية مع plat_service_contexts.
  • vndservice_contexts
    • service_context خاص بالجهاز لملف vndservicemanager تم إنشاؤه من خلال دمج vndservice_contexts المتوفّرة في الأدلة التي يشير إليها BOARD_SEPOLICY_DIRS في Boardconfig.mk الجهاز
    • يجب أن يكون هذا الملف مضمّنًا في قسم vendor في ‎ /vendor/etc/selinux/vndservice_contexts وأن يتم تحميله بواسطة ‎ vndservicemanager في البداية.

سياقات Seapp

في Android 8.0، يتم تقسيم seapp_contexts بين ملفين:

  • plat_seapp_contexts
    • نظام التشغيل Android seapp_context الذي لا يتضمّن تغييرات تخصّ الجهاز
    • يجب أن يكون مثبّتًا في القسم system على العنوان /system/etc/selinux/plat_seapp_contexts.
  • vendor_seapp_contexts
    • إضافة خاصة بالجهاز لمنصّة seapp_context تم إنشاؤها من خلال دمج seapp_contexts المتوفّرة في الدلائل التي يشير إليها BOARD_SEPOLICY_DIRS في ملفات Boardconfig.mk على الجهاز
    • يجب أن يكون مثبّتًا في القسم vendor على العنوان /vendor/etc/selinux/vendor_seapp_contexts.

أذونات MAC

في Android 8.0، يتم تقسيم mac_permissions.xml بين ملفين:

  • النظام الأساسي mac_permissions.xml
    • نظام التشغيل Android mac_permissions.xml الذي لا يتضمّن تغييرات خاصة بالجهاز
    • يجب أن يكون مثبّتًا في القسم system على العنوان /system/etc/selinux/.
  • غير مرتبطة بمنصّة معيّنة mac_permissions.xml
    • إضافة خاصة بالجهاز إلى النظام الأساسي mac_permissions.xml تم إنشاؤها من mac_permissions.xml في الأدلة التي يشير إليها BOARD_SEPOLICY_DIRS في ملفات Boardconfig.mk على الجهاز
    • يجب أن يكون مثبّتًا في القسم vendor على العنوان /vendor/etc/selinux/.