توضّح هذه الصفحة كيف يتعامل نظام التشغيل Android مع مشاكل توافق السياسات مع تحديثات النظام الأساسي عبر الأثير (OTA)، حيث قد تختلف إعدادات SELinux الجديدة للنظام الأساسي عن إعدادات SELinux القديمة الخاصة بالمورّد.
ملكية العناصر وتصنيفها
يجب تحديد الملكية بوضوح لكل عنصر للحفاظ على فصل سياسات المنصة والمورّد. على سبيل المثال، إذا كانت تصنيفات سياسة المورّد /dev/foo
وتصنيفات سياسة النظام الأساسي /dev/foo في تحديث لاحق عبر الأثير، سيحدث سلوك غير محدّد، مثل رفض غير متوقّع أو، بشكل أكثر خطورة، تعذُّر بدء التشغيل. بالنسبة إلى SELinux، يظهر ذلك على شكل تعارض في التصنيف. يمكن أن تحتوي عقدة الجهاز على تصنيف واحد فقط يتم تحديده حسب التصنيف الذي تم تطبيقه آخر مرة.
نتيجة لذلك:
- تفقد العمليات التي تحتاج إلى إذن الوصول إلى التصنيف الذي لم يتم تطبيقه بنجاح إذن الوصول إلى المورد.
- قد تتعطّل العمليات التي تصل إلى الملف بسبب إنشاء عقدة جهاز غير صحيحة.
يمكن أن تحدث تعارضات بين تصنيفات المنصة وتصنيفات المورّد لأي عنصر يتضمّن تصنيف SELinux، بما في ذلك الخصائص والخدمات والعمليات والملفات والمآخذ. لتجنُّب هذه المشاكل، حدِّد بوضوح ملكية هذه العناصر.
تحديد مساحة الاسم للنوع/السمة
بالإضافة إلى تعارضات التصنيفات، يمكن أن تتعارض أيضًا أسماء أنواع وسمات SELinux. لا يسمح SELinux بتعريفات متعدّدة للأنواع والسمات نفسها. لا يمكن تجميع سياسة تتضمّن بيانات مكرّرة. لتجنُّب حدوث تعارضات في النوع واسم السمة، ننصح بشدة بأن تبدأ جميع بيانات المورّدين التعريفية بالبادئة vendor_. على سبيل المثال، يجب أن يستخدم البائعون
type vendor_foo, domain; بدلاً من type foo, domain;.
ملكية الملف
يصعب منع حدوث تعارضات في الملفات لأنّ سياسة المنصة وسياسة المورّد توفّران عادةً تصنيفات لجميع أنظمة الملفات. على عكس تسمية الأنواع، لا يمكن تطبيق مساحة الاسم على الملفات لأنّ العديد منها يتم إنشاؤه بواسطة النواة. لمنع حدوث هذه التعارضات، اتّبِع إرشادات التسمية الخاصة بأنظمة الملفات في هذا القسم. بالنسبة إلى الإصدار 8.0 من نظام التشغيل Android، هذه مجرد اقتراحات بدون فرض قيود فنية. في المستقبل، سيتم فرض هذه الاقتراحات من خلال مجموعة اختبارات المورّد (VTS).
النظام (/system)
يجب أن توفّر صورة النظام تصنيفات لمكوّنات /system
من خلال file_contexts وservice_contexts وما إلى ذلك. وإذا تمت إضافة تصنيفات
لمكوّنات /system في سياسة المورّد، قد لا يكون من الممكن إجراء تحديث عبر الهواء خاص بالإطار فقط.
المورّد (/vendor)
تضع سياسة AOSP SELinux تصنيفات على أجزاء من قسم vendor
التي تتفاعل معها المنصة، ما يتيح كتابة قواعد SELinux لعمليات المنصة كي تتمكّن من التفاعل مع أجزاء من قسم vendor
أو الوصول إليها. أمثلة:
| /vendor path | التصنيف المقدَّم من المنصة | عمليات المنصة حسب التصنيف |
|---|---|---|
/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من خلال سياسة المورّد السمةvendor_file_type. ويتم فرض ذلك من خلال neverallows. - لتجنُّب حدوث تعارضات مع تحديثات المنصة/إطار العمل المستقبلية، تجنَّب تصنيف الملفات غير
exec_typesفي قسمvendor. - يجب تصنيف جميع تبعيات المكتبة الخاصة بحزم HAL التي تم تحديدها على أنّها عمليات مماثلة في AOSP على أنّها
same_process_hal_file.
Procfs (/proc)
يمكن تصنيف الملفات في /proc باستخدام التصنيف genfscon فقط. في نظام التشغيل Android 7.0، استخدمت كل من سياسة النظام الأساسي وسياسة المورّد الرمز genfscon لتصنيف الملفات في procfs.
الاقتراح: تصنيفات سياسات المنصات فقط /proc.
إذا كانت عمليات المورّد تتطلّب الوصول إلى ملفات في /proc مصنّفة حاليًا بالتصنيف التلقائي (proc)، يجب ألا تصنّف سياسة المورّد هذه الملفات بشكل صريح، بل يجب استخدام النوع العام proc لإضافة قواعد لنطاقات المورّدين. يتيح ذلك تعديل المنصة
لتتوافق مع واجهات النواة المستقبلية التي يتم عرضها من خلال
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. في الإصدار 7.0 من نظام التشغيل Android، تظهر تصنيفات المنصة فقط
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. في نظام التشغيل Android 7.0، يتوفّر هنا ملفات تصنيف كل من النظام الأساسي والمورّد.
اقتراح: يمكن للنظام فقط تصنيف الملفات في /.
البيانات (/data)
يتم تصنيف البيانات من خلال مزيج من file_contexts وseapp_contexts.
الاقتراح: عدم السماح بتصنيف البائعين خارج
/data/vendor. يمكن للمنصة فقط تصنيف الأجزاء الأخرى من
/data.
إصدار تصنيفات Genfs
بدءًا من مستوى واجهة برمجة التطبيقات الخاصة بالمورّد 202504، ستصبح تصنيفات SELinux الأحدث التي تم تعيينها باستخدام genfscon في system/sepolicy/compat/plat_sepolicy_genfs_ver.cil اختيارية لأقسام vendor الأقدم. ويسمح ذلك للأقسام القديمة
vendor بالاحتفاظ بتنفيذ SEPolicy الحالي.
يتم التحكّم في ذلك من خلال متغير Makefile BOARD_GENFS_LABELS_VERSION
المخزَّن في /vendor/etc/selinux/genfs_labels_version.txt.
مثال:
-
في مستوى واجهة برمجة التطبيقات للمورّد 202404، يتم تصنيف العقدة
/sys/class/udcعلى أنّهاsysfsتلقائيًا. -
اعتبارًا من مستوى واجهة برمجة التطبيقات الخاصة بالمورّد 202504، سيتم تصنيف
/sys/class/udcعلى أنّهsysfs_udc.
ومع ذلك، قد يكون /sys/class/udc قيد الاستخدام من خلال أقسام vendor
باستخدام مستوى واجهة برمجة التطبيقات 202404، إما مع التصنيف التلقائي sysfs
أو تصنيف خاص بمورّد معيّن. قد يؤدي تصنيف /sys/class/udc على أنّه sysfs_udc بشكل غير مشروط إلى حدوث مشاكل في التوافق مع أقسام vendor هذه. من خلال وضع علامة في المربّع
BOARD_GENFS_LABELS_VERSION، تواصل المنصة استخدام التصنيفات والأذونات السابقة لأقسام vendor القديمة.
يمكن أن يكون BOARD_GENFS_LABELS_VERSION أكبر من أو يساوي مستوى واجهة برمجة التطبيقات الخاصة بالمورّد. على سبيل المثال، يمكن للأقسام vendor التي تستخدم مستوى واجهة برمجة التطبيقات 202404 ضبط BOARD_GENFS_LABELS_VERSION على 202504 لاستخدام التصنيفات الجديدة التي تم طرحها في 202504. اطّلِع على قائمة
تصنيفات genfs الخاصة بـ 202504.
عند تصنيف عقد genfscon، يجب أن تأخذ المنصة في الاعتبار أقسام vendor الأقدم وتنفّذ آليات احتياطية لتحقيق التوافق عند الحاجة. يمكن للمنصة استخدام مكتبات خاصة بالمنصة فقط للاستعلام عن إصدار تصنيفات genfs.
-
في الإعلانات المدمجة مع المحتوى، استخدِم
libgenfslabelsversion. يمكنك الاطّلاع علىgenfslabelsversion.hلمعرفة ملف العنوان الخاص بـlibgenfslabelsversion. -
في Java، استخدِم
android.os.SELinux.getGenfsLabelsVersion().
السياسة العامة على مستوى المنصة
تنقسم سياسة SELinux الخاصة بالمنصة إلى قسمَين: خاص وعام. تتألف سياسة
المنصة العامة من أنواع وسمات تكون متاحة دائمًا
لمستوى واجهة برمجة التطبيقات الخاصة بالمورّد،
وتعمل كواجهة برمجة تطبيقات بين المنصة والمورّد. تتوفّر هذه السياسة لمطوّري سياسات المورّدين، ما يتيح للمورّدين إنشاء ملفات سياسات المورّدين التي تؤدي عند دمجها مع السياسة الخاصة بالمنصة إلى إنشاء سياسة تعمل بكامل طاقتها على الجهاز. يتم تحديد سياسة المنصة العامة في
system/sepolicy/public.
على سبيل المثال، يتم تحديد النوع vendor_init، الذي يمثّل عملية init في سياق المورّد، ضمن system/sepolicy/public/vendor_init.te:
type vendor_init, domain;
يمكن للمورّدين الرجوع إلى النوع vendor_init لكتابة قواعد سياسة مخصّصة:
# Allow vendor_init to set vendor_audio_prop in vendor's init scripts
set_prop(vendor_init, vendor_audio_prop)سمات التوافق
سياسة SELinux هي تفاعل بين أنواع المصدر والهدف لفئات وأذونات كائنات معيّنة. يمكن أن يكون لكل عنصر (مثل العمليات والملفات) متأثر بسياسة SELinux نوع واحد فقط، ولكن قد يتضمّن هذا النوع سمات متعددة.
تتم كتابة السياسة في الغالب من حيث الأنواع الحالية. في ما يلي، يمثّل كل من vendor_init وdebugfs نوعًا:
allow vendor_init debugfs:dir { mounton };
يعمل هذا الإجراء لأنّ السياسة كُتبت مع معرفة جميع الأنواع. ومع ذلك،
إذا كانت سياسة المورّد وسياسة المنصّة تستخدمان أنواعًا معيّنة، وتغيّر تصنيف عنصر معيّن في إحدى السياسات فقط، قد تحتوي السياسة الأخرى على سياسة اكتسبت أو فقدت إذن الوصول الذي كان معتمدًا سابقًا. على سبيل المثال، لنفترض أنّ تصنيفات سياسة النظام الأساسي تصنّف عقد sysfs على النحو التالي: sysfs:
/sys(/.*)? u:object_r:sysfs:s0
تمنح سياسة المورّد إذن الوصول إلى /sys/usb، ويتم تصنيفها على النحو التالي:
sysfs:
allow vendor_init sysfs:chr_file rw_file_perms;
إذا تم تغيير سياسة المنصة إلى تصنيف /sys/usb على أنّه sysfs_usb، ستبقى سياسة المورّد كما هي، ولكن سيتم حظر وصول vendor_init إلى /sys/usb بسبب عدم توفّر سياسة لنوع sysfs_usb الجديد:
/sys/usb u:object_r:sysfs_usb:s0
لحلّ هذه المشكلة، يقدّم نظام التشغيل Android مفهوم السمات المستندة إلى الإصدار. أثناء وقت التجميع، يترجم نظام التصميم تلقائيًا الأنواع العامة للنظام الأساسي المستخدَمة في سياسة المورّد إلى هذه السمات المتوافقة مع الإصدار. يتم تفعيل هذه الترجمة من خلال ربط الملفات التي تربط سمة ذات إصدار بنوع واحد أو أكثر من الأنواع العامة من المنصة.
على سبيل المثال، لنفترض أنّ /sys/usb مصنّف على أنّه sysfs
في سياسة المنصة 202504، وأنّ سياسة المورّد 202504 تمنح
vendor_init إذن الوصول إلى /sys/usb. في هذه الحالة:
-
تكتب سياسة المورّد قاعدة
allow vendor_init sysfs:chr_file rw_file_perms;، لأنّ/sys/usbمصنّف على أنّهsysfsفي سياسة المنصّة 202504. عندما يجمع نظام التصميم سياسة المورّد، يترجم القاعدة تلقائيًا إلىallow vendor_init_202504 sysfs_202504:chr_file rw_file_perms;. تتطابق السمتانvendor_init_202504وsysfs_202504مع النوعينvendor_initوsysfs، وهما النوعان اللذان يحددهما النظام الأساسي. -
ينشئ نظام التصميم ملف ربط بتنسيق CSV لتحديد الهوية
/system/etc/selinux/mapping/202504.cil. بما أنّ كلّاً من القسمَينsystemوvendorيستخدمان الإصدار202504نفسه، يحتوي ملف الربط على عمليات ربط الهوية منtype_202504إلىtype. على سبيل المثال، يتم ربطvendor_init_202504بـvendor_init، ويتم ربطsysfs_202504بـsysfs:(typeattributeset sysfs_202504 (sysfs)) (typeattributeset vendor_init_202504 (vendor_init)) ...
عندما يتم تغيير الإصدار من 202504 إلى 202604، يتم إنشاء ملف ربط جديد لأقسام 202504
vendor ضمن
system/sepolicy/private/compat/202504/202504.cil، ويتم تثبيته في /system/etc/selinux/mapping/202504.cil لأقسام 202604
أو الأحدث system. في البداية، يحتوي ملف الربط هذا على عمليات ربط المعرّفات، كما هو موضّح سابقًا. في حال تمت إضافة تصنيف جديد sysfs_usb
لـ /sys/usb إلى سياسة المنصة 202604، سيتم تعديل ملف الربط
لربط sysfs_202504 بـ sysfs_usb:
(typeattributeset sysfs_202504 (sysfs sysfs_usb)) (typeattributeset vendor_init_202504 (vendor_init)) ...
يتيح هذا التعديل لقاعدة سياسة المورّد المحوَّلة allow
vendor_init_202504 sysfs_202504:chr_file rw_file_perms; أن تمنح تلقائيًا إذن الوصول إلى النوع الجديد sysfs_usb.vendor_init
للحفاظ على التوافق مع أقسام vendor القديمة، يجب ربط أي نوع عام جديد يتم إضافته بسمة واحدة على الأقل من السمات التي تتضمّن رقم الإصدار في ملف الربط system/sepolicy/private/compat/ver/ver.cil، أو إدراجه ضمن system/sepolicy/private/compat/ver/ver.ignore.cil لتوضيح أنّه لا يوجد نوع مطابق في إصدارات المورّد السابقة.
يسمح الجمع بين سياسة النظام الأساسي وسياسة المورّد وملف التعيين للنظام بالتحديث بدون تعديل سياسة المورّد. بالإضافة إلى ذلك، يتم التحويل إلى السمات المتوافقة مع الإصدار تلقائيًا، لذا لا تحتاج سياسة المورّد إلى الاهتمام بالتوافق مع الإصدار، بل يمكنها مواصلة استخدام الأنواع العامة كما هي.
سياسة system_ext العامة وسياسة المنتجات العامة
بدءًا من Android 11، يُسمح للقسمَين system_ext وproduct بتصدير الأنواع العامة المحدّدة إلى القسم vendor. مثل سياسة المنصة العامة، تستخدم سياسة المورّد الأنواع والقواعد التي تتم ترجمتها تلقائيًا إلى السمات التي تتضمّن إصدارات، مثلاً من type إلى type_ver، حيث ver هو مستوى واجهة برمجة التطبيقات للمورّد في قسم vendor.
عندما يستند كل من القسمين system_ext وproduct إلى إصدار النظام الأساسي نفسه ver، ينشئ نظام التصميم ملفات ربط أساسية لكل من system_ext/etc/selinux/mapping/ver.cil وproduct/etc/selinux/mapping/ver.cil، تحتوي على عمليات ربط الهوية من type إلى type_ver.
يمكن أن تصل سياسة المورّد إلى type باستخدام السمة التي تتضمّن رقم الإصدار type_ver.
في حال تعديل القسمَين system_ext وproduct فقط، مثلاً من ver إلى ver+1 (أو إصدار أحدث)، مع بقاء القسم vendor على الإصدار ver، قد تفقد سياسة المورّد إذن الوصول إلى أنواع القسمَين system_ext وproduct. لمنع حدوث أي مشاكل، يجب أن يوفّر القسمان
system_ext وproduct ملفات ربط من الأنواع المحدّدة إلى سمات type_ver. يكون كل شريك مسؤولاً عن الحفاظ على ملفات الربط
في حال كان الجهاز يتيح استخدام قسم ver vendor مع
ver+1 (أو إصدار أحدث) system_ext وأقسام product.
لتثبيت ملفات الربط في القسمَين system_ext وproduct، يُتوقّع من مطوّري الأجهزة أو المورّدين اتّباع الخطوات التالية:
- انسخ ملفات ربط قاعدة البيانات التي تم إنشاؤها من الأقسام ver
system_extوproductإلى شجرة المصدر. - عدِّل ملفات الربط حسب الحاجة.
-
ثبِّت ملفات الربط على الأقسام ver+1 (أو إصدار أحدث)
system_extوproduct.
على سبيل المثال، لنفترض أنّ القسم 202504 system_ext يحتوي على نوع عام واحد باسم foo_type. بعد ذلك، سيبدو القسم system_ext الذي يحمل الرقم 202504 على النحو التالي:system_ext/etc/selinux/mapping/202504.cil
(typeattributeset foo_type_202504 (foo_type)) (expandtypeattribute foo_type_202504 true) (typeattribute foo_type_202504)
في حال إضافة bar_type إلى القسم system_ext الذي يحمل الاسم 202604، وفي حال كان من المفترض ربط bar_type بـ foo_type للقسم vendor الذي يحمل الاسم 202504، يمكن تعديل 202504.cil من (typeattributeset foo_type_202504 (foo_type)) إلى (typeattributeset foo_type_202504 (foo_type bar_type))، ثم تثبيته في القسم system_ext الذي يحمل الاسم 202604. يمكن أن يستمر قسم 202504
vendor في الوصول إلى foo_type وbar_type في قسم 202604
system_ext.
تغييرات السمات في 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) التي تخالف شرط عدم تنفيذ ملفات ثنائية خاصة بمورّدين. تنفيذ ملفات ثنائية خاصة بمورّدين تتضمّن واجهة برمجة تطبيقات غير ثابتة يجب ألا تنفّذ المنصة ملفات ثنائية خاصة بالمورّد مباشرةً. التوصية:- يجب أن تكون عمليات الربط بين المنصات وثنائيات المورّدين في الخلفية من خلال طبقات تجريد الأجهزة (HAL) لواجهة HIDL.
أو
- يجب نقل
coredomainsالتي تحتاج إلى الوصول إلى الرموز الثنائية الخاصة بالمورّد إلى قسمvendor، وبالتالي، التوقف عن كونهاcoredomain.
- يجب أن تكون عمليات الربط بين المنصات وثنائيات المورّدين في الخلفية من خلال طبقات تجريد الأجهزة (HAL) لواجهة HIDL.
السمات غير الموثوق بها
يجب ألا تتمكّن التطبيقات غير الموثوق بها التي تستضيف رموزًا برمجية عشوائية من الوصول إلى خدمات HwBinder، باستثناء تلك التي تُعتبر آمنة بدرجة كافية للوصول إليها من هذه التطبيقات (راجِع الخدمات الآمنة أدناه). في ما يلي السببان الرئيسيان لذلك:
- لا تنفّذ خوادم HwBinder مصادقة العميل لأنّ HIDL لا تعرض حاليًا معلومات UID الخاصة بالمتصل. وحتى إذا كان HIDL يعرض مثل هذه البيانات، فإنّ العديد من خدمات HwBinder إما تعمل على مستوى أقل من مستوى التطبيقات (مثل طبقات تجريد الأجهزة) أو يجب ألا تعتمد على هوية التطبيق في عملية التفويض. وبالتالي، ولتجنُّب أي مشاكل، يتم تلقائيًا افتراض أنّ كل خدمة من خدمات HwBinder تعامل جميع عملائها على أنّهم مخوّلون بالتساوي لإجراء العمليات التي تقدّمها الخدمة.
- تحتوي خوادم HAL (مجموعة فرعية من خدمات HwBinder) على رمز يتضمّن معدل حدوث أعلى للمشاكل الأمنية مقارنةً بمكوّنات
system/core، كما يمكنها الوصول إلى الطبقات السفلية من الحزمة (حتى الأجهزة)، ما يزيد من فرص تجاوز نموذج أمان Android.
الخدمات الآمنة
تشمل الخدمات الآمنة ما يلي:
same_process_hwservice. تعمل هذه الخدمات (بحكم تعريفها) في عملية العميل، وبالتالي يكون لديها إذن الوصول نفسه إلى نطاق العميل الذي تعمل فيه العملية.coredomain_hwservice، ولا تشكّل هذه الخدمات أي مخاطر مرتبطة بالسبب رقم 2.hal_configstore_ISurfaceFlingerConfigs، وهي خدمة مصمّمة خصيصًا ليستخدمها أي نطاق.hal_graphics_allocator_hwservice. تقدّم خدمةsurfaceflingerBinder هذه العمليات أيضًا، ويُسمح للتطبيقات بالوصول إليها.-
hal_omx_hwservice، وهو إصدار HwBinder من خدمةmediacodecBinder التي يُسمح للتطبيقات بالوصول إليها. -
hal_codec2_hwserviceهو إصدار أحدث منhal_omx_hwservice.
السمات القابلة للاستخدام
تحتوي جميع hwservices التي لا تُعتبر آمنة على السمة untrusted_app_visible_hwservice. تحتوي خوادم HAL المقابلة على السمة untrusted_app_visible_halserver. يجب ألا تستخدم الأجهزة التي تعمل بالإصدار 9 من نظام التشغيل Android أيًا من سمات untrusted.
الاقتراح:
- بدلاً من ذلك، يجب أن تتواصل التطبيقات غير الموثوق بها مع خدمة تابعة لنظام التشغيل تتواصل مع طبقة HAL الخاصة بمورّد HIDL. على سبيل المثال، يمكن للتطبيقات التحدّث إلى
binderservicedomain، ثم يتحدّثmediaserver(وهوbinderservicedomain) بدوره إلىhal_graphics_allocator.أو
- يجب أن تتضمّن التطبيقات التي تحتاج إلى الوصول المباشر إلى
vendorHALs نطاق sepolicy خاصًا بها يحدّده المورّد.
اختبارات سمات الملفات
يتضمّن نظام التشغيل Android 9 اختبارات مدّة التصميم تضمن احتواء جميع الملفات في مواقع جغرافية معيّنة على السمات المناسبة (مثل احتواء جميع الملفات في sysfs على السمة sysfs_type المطلوبة).
تصنيف سياقات SELinux
ولإتاحة التمييز بين سياسات 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الخاص بالمورّد.
- نظام Android الأساسي
vendor_file_contextsfile_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.
- نظام Android الأساسي
vendor_property_contextsproperty_contextخاص بالجهاز تم إنشاؤه من خلال الجمع بينproperty_contextsالموجودة في الأدلة التي تشير إليهاBOARD_SEPOLICY_DIRSفي ملفاتBoardconfig.mkالجهاز.- يجب أن يكون موجودًا في قسم
vendorفي/vendor/etc/selinux/vendor_property_contextsوأن يتم تحميله بواسطةinitفي البداية معproperty_contextللنظام الأساسي
سياقات الخدمة
في نظام التشغيل Android 8.0، يتم تقسيم service_contexts بين الملفات التالية:
plat_service_contextsservice_contextالخاصة بنظام Android الأساسيservicemanagerلا يحتويservice_contextعلى أي تصنيفات خاصة بالجهاز.- يجب أن يكون في القسم
systemفي/system/etc/selinux/plat_service_contextsوأن يتم تحميله بواسطةservicemanagerفي البداية معservice_contexts.
vendor_service_contextsservice_contextخاص بالجهاز تم إنشاؤه من خلال الجمع بينservice_contextsالتي تم العثور عليها في الأدلة التي تشير إليهاBOARD_SEPOLICY_DIRSفيBoardconfig.mkالخاصة بالجهاز.- يجب أن يكون في القسم
vendorفي/vendor/etc/selinux/vendor_service_contextsوأن يتم تحميله بواسطةservicemanagerفي البداية معservice_contexts. - على الرغم من أنّ
servicemanagerيبحث عن هذا الملف عند بدء التشغيل، يجب ألا يتوفّرvendor_service_contextsفي جهازTREBLEمتوافق تمامًا. ويرجع ذلك إلى أنّ جميع التفاعلات بين العمليتَينvendorوsystemيجب أن تمر عبرhwservicemanager/hwbinder.
plat_hwservice_contexts- نظام Android الأساسي
hwservice_contextالذيhwservicemanagerلا يحتوي على تصنيفات خاصة بالجهاز. - يجب أن يكون في القسم
systemفي/system/etc/selinux/plat_hwservice_contextsوأن يتم تحميله بواسطةhwservicemanagerفي البداية معvendor_hwservice_contexts.
- نظام Android الأساسي
vendor_hwservice_contextshwservice_contextخاص بالجهاز تم إنشاؤه من خلال الجمع بينhwservice_contextsالتي تم العثور عليها في الأدلة التي تشير إليهاBOARD_SEPOLICY_DIRSفيBoardconfig.mkالخاصة بالجهاز.- يجب أن يكون الملف في القسم
vendorفي/vendor/etc/selinux/vendor_hwservice_contextsوأن يتم تحميله بواسطةhwservicemanagerفي البداية معplat_service_contexts.
vndservice_contextsservice_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.
- نظام Android الأساسي
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/.
- نظام Android الأساسي
- غير تابع للمنصة
mac_permissions.xml- إضافة خاصة بالجهاز إلى النظام الأساسي
mac_permissions.xmlتم إنشاؤها منmac_permissions.xmlتم العثور عليها في الدلائل التي يشير إليهاBOARD_SEPOLICY_DIRSفي ملفاتBoardconfig.mkبالجهاز. - يجب أن يكون مقيمًا في القسم
vendorعند/vendor/etc/selinux/.
- إضافة خاصة بالجهاز إلى النظام الأساسي
تغييرات الذاكرة المشتركة في Android 17
بدءًا من الإصدار 17 من نظام التشغيل Android، يجب أن تفعّل الأجهزة التي يتم طرحها بالخصائص التالية إمكانية استخدام سياسة memfd_class، وأن تعدّل السياسة ذات الصلة بالذاكرة المشتركة لتتوافق مع عناصر الفئة memfd_file:
- المستوى 202604 أو أعلى من واجهة برمجة التطبيقات الخاصة بالمورِّدين لمنح المورِّدين ومصنّعي المعدات الأصلية فرصة تعديل سياسة المورِّدين لتتوافق مع
memfdكما يتيح ترقية الأجهزة الحالية إلى إصدارات أعلى من Android بدون الحاجة إلى تحديث قسم المورّد. android16-6.12أو إصدار أحدث من النواة، لأنّ هذه النواة تتوافق مع ميزةmemfd_classالمطلوبة لتنفيذ سياسة دقيقة بشأنmemfd.
تفعيل إمكانية سياسة memfd_class
حتى وقت قريب، كان SELinux يصنّف memfd كملف من النوع نفسه الذي يستخدمه نظام الملفات الأساسي، أي tmpfs. وقد أدّى ذلك إلى استحالة التمييز بين memfd وملف آخر على وحدة تخزين tmpfs من منظور السياسة. الآن، تصنّف SELinux memfd حسب سياق الأمان لعملية التخصيص، ويتم التعامل مع memfds ككائنات من فئة memfd_file. يتم حماية هذه الوظيفة من خلال إمكانية سياسة memfd_class للحفاظ على التوافق مع بيئات مساحة المستخدم القديمة.
لتفعيل إمكانية استخدام سياسة memfd_class، أنشئ ملف policy_capabilities ضمن BOARD_VENDOR_SEPOLICY_DIRS. يجب أن يحتوي الملف على الإدخال التالي:
# $BOARD_VENDOR_SEPOLICY_DIRS/*/policy_capabilities
policycap memfd_class;بعد ذلك، أعِد إنشاء الصور وثبِّتها على جهازك للتأكّد من تفعيل هذه الإمكانية.
التأكّد من تفعيل إمكانية سياسة memfd_class
استخدِم الأمر التالي للتحقّق من حالة إمكانية سياسة memfd_class:
adb shell 'cat /sys/fs/selinux/policy_capabilities/memfd_class'
إذا كانت النتيجة 1، يتم تفعيل إمكانية سياسة memfd_class. وفي الحالات الأخرى، لن يتم تفعيله.
نقل السياسة الحالية إلى memfd
استخدمت بعض العمليات وحدة الماكرو tmpfs_domain() في سياستها للوصول إلى memfds وتحديد مساحتها، على سبيل المثال:
# foo.te
tmpfs_domain(foo)ويعني ذلك ما يلي:
# foo.te type_transition foo tmpfs:file foo_tmpfs; allow foo foo_tmpfs:file { read write getattr map };
ويسمح بمعالجة bar عملية الوصول إلى العملية foo على النحو التالي:memfds
# bar.te allow bar foo_tmpfs:file { read write getattr map };
بعد تفعيل إمكانية سياسة memfd_class، لم يعُد الماكرو tmpfs_domain() مطلوبًا، لأنّه تم تعديل سياسة النظام الأساسي للسماح لأي عملية بإنشاء واستخدام memfds الخاص بها، كما هو موضّح هنا:
# system/sepolicy/private/domain.te allow domain self:memfd_file { create read write getattr map };
ويمكن للعملية bar الوصول إلى memfds التي أنشأتها العملية foo على النحو التالي:
# bar.te allow bar foo:memfd_file { read write getattr map };
تم تعديل سياسة المنصة لتراعي الاستخدامات الحالية لـ memfd. ومع ذلك، يجب تعديل السياسات الخاصة بمورّد أو جهاز معيّن والتي تستخدم التصنيفات tmpfs لاستخدام memfd_file. إذا كانت السياسة مشترَكة بين منظومات على رقاقة (SoC) أو الأجهزة التي لا يتوفّر فيها مستوى واجهة برمجة التطبيقات الخاص بالمورّد 202604 أو أعلى، يُنصح بالاحتفاظ بسياسة tmpfs القديمة إلى جانب سياسة memfd_file الجديدة لضمان التوافق.
تحديد عمليات الرفض المرتبطة بـ memfd في AVC
يمكن استرداد عمليات الرفض المرتبطة بـ Memfd باستخدام الأمر التالي:
adb shell logcat -d -b events | grep memfd
رفض AVC مع استخدام tmpfs كهدف
يعرض المثال التالي عملية avc رفض واجهتها عملية حاولت الكتابة إلى memfd ليس لديها إذن بالكتابة إليه:
audit(0.0:539): avc: denied { write } for comm="binder:665_1" name="memfd:MessageQueue"
dev="tmpfs" ino=8324 scontext=u:r:mediacodec:s0 tcontext=u:object_r:tmpfs:s0 tclass=file
permissive=0
عند تفعيل إمكانية سياسة memfd_class، يكون سياق الهدف لـ memfd هو سياق أمان عملية التخصيص، وليس tmpfs، ويكون فئة الهدف هي memfd_file، وليس file. لذلك، إذا كنت تلاحظ حالات رفض مرتبطة avcmemfd، وكان memfd المعنيّ مصنّفًا على أنّه ملف tmpfs، فهذا يعني أنّ إمكانية تطبيق سياسة memfd_class غير مفعّلة.
عمليات رفض AVC التي تستخدم memfd_file كفئة مستهدَفة
يعرض المثال التالي رفضًا لطلب avc صادفَته عملية تحاول الكتابة إلى memfd ليس لديها إذن بالكتابة إليه، وتم تفعيل إمكانية سياسة memfd_class، بالإضافة إلى سطر إضافي ترسله logd بعد الرفض مع الطابع الزمني نفسه:
audit(0.0:86): avc: denied { read } for
path=2F6D656D66643A4D6564696142756666657247726F7570202864656C6574656429 ino=512 dev=""
scontext=u:r:mediaserver:s0 tcontext=u:object_r:mediaextractor:s0 tclass=memfd_file
auditd : Decoded path for audit(0.0:86): /memfd:MediaBufferGroup (deleted)
يشير الطابع الزمني المطابق إلى أنّ Decoded path for … log مرتبط بالرفض avc الذي يحمل الطابع الزمني 0.0.86. يفكّ هذا السجلّ ترميز السلسلة السداسية العشرية من قيمة المسار في رفض avc، ويقدّم اسم منطقة الذاكرة memfd، ما قد يكون مفيدًا لفهم المخزن المؤقت الذي تتم مشاركته. يكون سياق المصدر وسياق الهدف مفيدَين لفهم العمليات التي تحتاج إلى مشاركة الذاكرة. من المثال السابق، من الواضح أنّ العملية mediaserver يجب أن تتمكّن من الوصول إلى memfds في mediaextractor. وبالتالي، تكون السياسة المناسبة هي:
# mediaserver.te allow mediaserver mediaextractor:memfd_file { getattr read write map };
تعديلات على نطاق الأمان في Android 17
تنفّذ واجهة برمجة التطبيقات ASharedMemory_create() في Android 17 منطقًا شرطيًا للاختيار بين برنامج تشغيل ashmem القديم وإطار عمل memfd لعمليات تخصيص الذاكرة المشتركة.
بالنسبة إلى الأجهزة التي تستوفي متطلبات memfd (مستوى واجهة برمجة التطبيقات 202604 أو أعلى الخاص بالمورّد ونواة android16-6.12 أو أحدث)، تقيِّم واجهة برمجة التطبيقات targetSdkVersion للتطبيق الذي يستدعيها. إذا كان إصدار حزمة تطوير البرامج (SDK) المستهدَف هو 37 أو إصدارًا أحدث، يتم تخصيص memfd. ويسمح ذلك للمطوّرين بحلّ المشاكل التي يواجهونها أثناء ترقية إصدار حزمة SDK المستهدَفة.
إذا لم يستوفِ الجهاز متطلبات memfd's الأساسية، سيتم استخدام ashmem بدلاً من ASharedMemory. ويحافظ ذلك على التوافق مع الأجهزة التي تمت ترقيتها والتي تتضمّن أقسامًا أو نِوى قديمة خاصة بالمورّد.
لفرض هذا الانتقال، تمنع سياسة SELinux الأساسية التطبيقات التي تستهدف الإصدار 37 أو إصدارًا أحدث من حزمة تطوير البرامج (SDK) في نطاقات الأمان platform_app وpriv_app وuntrusted_app من فتح /dev/ashmem واستدعاء أوامر ashmem ioctl على memfd. ويتم تحقيق ذلك من خلال تقسيم نطاقات التطبيقات هذه استنادًا إلى إصدار حزمة تطوير البرامج (SDK) المستهدَف. يقدّم هذا التحديث نطاقات الأمان platform_app_36 وpriv_app_36 وuntrusted_app_34 التي تحتفظ، إلى جانب نطاقات التطبيقات الأخرى، بأذونات فتح ashmem وإمكانية استدعاء أوامر ashmem ioctl على memfds.
في إصدار Android مستقبلي، سيتم تقليل مجموعة التطبيقات التي تحتفظ بأذونات فتح جهاز ashmem واستدعاء أوامر ashmem ioctl على memfds إلى platform_app_36 وpriv_app_36 وuntrusted_app_34 فقط ونطاقات التطبيقات غير الموثوق بها لإصدارات حزمة SDK القديمة.
يجب تعديل سياسات SELinux المخصّصة للمورّدين أو مصنّعي المعدات الأصلية (OEM) للتطبيقات التي تثبّت إصدار حزمة تطوير البرامج (SDK) المستهدَف ليتوافق مع تغييرات النطاق هذه، كما هو موضّح بالتفصيل في الأقسام التالية.
تعديلات على نطاق SELinux الخاص بتطبيق platform_app
يتم تقسيم النطاق platform_app استنادًا إلى targetSdkVersion للتطبيق. يتم تخصيص النطاق platform_app لتطبيقات المنصة التي تستهدف الإصدار 37 من حزمة تطوير البرامج (SDK) أو إصدارًا أحدث، بينما تستخدم التطبيقات التي تستهدف الإصدار 36 من حزمة تطوير البرامج (SDK) أو إصدارًا أقدم النطاق platform_app_36. يحتفظ النطاق platform_app_36 بإمكانية فتح /dev/ashmem من أجل التوافق مع الأنظمة القديمة. لتسهيل إدارة السياسات على مستوى كلا النطاقَين، استخدِم السمة platform_app_all.
لنفترض أنّ تطبيق النظام الأساسي sample-plat-app يحتاج إلى القراءة والكتابة من وإلى /dev/foo_device. قد تبدو سياسة SELinux الحالية الخاصة بالمورّد على النحو التالي:
# This will only allow sample-plat-app to access the device if it # is placed in the platform_app domain (i.e. target SDK version is 37 or higher). allow platform_app foo_device:chr_file rw_file_perms;
ومع ذلك، إذا تم تثبيت sample-plat-app على الإصدار 36 من حزمة تطوير البرامج (SDK) المستهدَفة، سيتم وضعه في النطاق platform_app_36، ولن يتم تطبيق سياسة SELinux من الإصدارات السابقة، وسيتم رصد رفض AVC التالي:
auditd : type=1400 audit(0.0:11): avc: denied { read write } for comm="sample-plat-app" path="/dev/foo_device" dev="tmpfs" ino=1609 scontext=u:r:platform_app_36:s0:c512,c768 tcontext=u:object_r:foo_device:s0 tclass=chr_file permissive=0
لحلّ هذه المشكلة، يمكن تعديل السياسة على النحو التالي بما أنّ التطبيق يجب أن يتمكّن دائمًا من الوصول إلى عقدة الجهاز:
# This allows sample-plat-app to access the device independent of # target SDK version. allow platform_app_all foo_device:chr_file rw_file_perms;
قد لا تعمل ميزة platform_app_all في بعض الحالات. على سبيل المثال، إذا تم استخدام ماكرو hal_client_domain() مع platform_app_all، سيتعذّر تجميع السياسة. يرجع ذلك إلى أنّ platform_app_all هي سمة، وستحاول hal_client_domain() إرفاق سمة أخرى بها، وهو أمر غير ممكن:
# platform_app.te
hal_client_domain(platform_app, hal_foo)
في هذه الحالات، يجب استخدام النوع platform_app_36 مباشرةً، لذا يجب أن تتضمّن سياستك المحتوى التالي:
# platform_app.te hal_client_domain(platform_app, hal_foo) # platform_app_36.te hal_client_domain(platform_app_36, hal_foo)
تعديلات على نطاق SELinux الخاص بالتطبيقات ذات الامتيازات
يتم تقسيم النطاق priv_app استنادًا إلى targetSdkVersion للتطبيق. يتم تخصيص النطاق priv_app للتطبيقات ذات الأذونات المميزة التي تستهدف الإصدار 37 من حزمة تطوير البرامج (SDK) أو إصدارًا أحدث، بينما تستخدم التطبيقات التي تستهدف الإصدار 36 من حزمة تطوير البرامج (SDK) أو إصدارًا أقدم النطاق priv_app_36. يحتفظ النطاق priv_app_36 بإمكانية فتح /dev/ashmem من أجل التوافق مع الأنظمة القديمة. لتسهيل إدارة السياسات على مستوى كلا النطاقَين، استخدِم السمة priv_app_all.
لنفترض أنّ تطبيق النظام الأساسي sample-priv-app يحتاج إلى القراءة والكتابة من وإلى /dev/foo_device. قد تبدو سياسة SELinux الحالية الخاصة بالمورّد على النحو التالي:
# This will only allow sample-priv-app to access the device if it # is placed in the priv_app domain (i.e. target SDK version is 37 or higher). allow priv_app foo_device:chr_file rw_file_perms;
ومع ذلك، إذا تم تثبيت sample-priv-app على الإصدار 36 من حزمة تطوير البرامج (SDK) المستهدَفة، سيتم وضعه في النطاق priv_app_36، ولن يتم تطبيق سياسة SELinux من الإصدارات السابقة، وسيتم رصد رفض AVC التالي:
auditd : type=1400 audit(0.0:11): avc: denied { read write } for comm="sample-priv-app" path="/dev/foo_device" dev="tmpfs" ino=1609 scontext=u:r:priv_app_36:s0:c512,c768 tcontext=u:object_r:foo_device:s0 tclass=chr_file permissive=0
لحلّ هذه المشكلة، يمكن تعديل السياسة على النحو التالي بما أنّ التطبيق يجب أن يتمكّن دائمًا من الوصول إلى عقدة الجهاز:
# This allows sample-priv-app to access the device independent of # target SDK version. allow priv_app_all foo_device:chr_file rw_file_perms;
قد لا تعمل ميزة priv_app_all في بعض الحالات. على سبيل المثال، إذا تم استخدام ماكرو hal_client_domain() مع priv_app_all، سيتعذّر تجميع السياسة. يرجع ذلك إلى أنّ priv_app_all هي سمة، وستحاول hal_client_domain() إرفاق سمة أخرى بها، وهو أمر غير ممكن:
# priv_app.te
hal_client_domain(priv_app, hal_foo)
في هذه السيناريوهات، يجب استخدام النوع priv_app_36 مباشرةً، لذا ستظهر ملفات السياسات على النحو التالي:
# priv_app.te hal_client_domain(priv_app, hal_foo) # priv_app_36.te hal_client_domain(priv_app_36, hal_foo)
تعديلات على نطاق SELinux الخاص بتطبيق untrusted_app
يتم تقسيم النطاق untrusted_app استنادًا إلى targetSdkVersion للتطبيق. يتم تخصيص النطاق untrusted_app للتطبيقات غير الموثوق بها التي تستهدف الإصدار 37 من حزمة تطوير البرامج (SDK) أو إصدارًا أحدث، بينما يتم تخصيص النطاق الجديد untrusted_app_34 للتطبيقات التي تستهدف الإصدارات من 34 إلى 36 ضِمنًا. يحتفظ النطاق untrusted_app_34، بالإضافة إلى النطاقات untrusted_app_X، حيث يمثّل X إصدارًا قديمًا من حزمة SDK المستهدَفة، بإمكانية فتح `/dev/ashmem` لتحقيق التوافق مع الإصدارات القديمة.