فرآیند init تقریباً مجوزهای نامحدودی دارد و از اسکریپتهای ورودی از پارتیشنهای سیستم و فروشنده برای مقداردهی اولیه سیستم در طول فرآیند بوت استفاده میکند. این دسترسی باعث ایجاد حفره بزرگی در تقسیم سیستم/فروشنده Treble میشود، زیرا اسکریپتهای فروشنده ممکن است به init دستور دهند که به فایلها، ویژگیها و غیره دسترسی پیدا کند که بخشی از رابط باینری برنامه پایدار سیستم-فروشنده (ABI) را تشکیل نمیدهند.
Vendor init طوری طراحی شده است که این حفره را با استفاده از یک دامنه جداگانه لینوکس (SELinux) تقویتشده با امنیت، vendor_init
برای اجرای دستورات موجود در /vendor
با مجوزهای خاص فروشنده، ببندد.
مکانیسم
Init فروشنده یک فرآیند فرعی از init را در اوایل فرآیند بوت با زمینه SELinux u:r:vendor_init:s0
ایجاد می کند. این زمینه SELinux دارای مجوزهای بسیار کمتری نسبت به زمینه اولیه پیشفرض است و دسترسی آن به فایلها، ویژگیها، و غیره محدود میشود که یا مختص فروشنده هستند یا بخشی از سیستم فروشنده پایدار ABI هستند.
Init هر اسکریپتی را که بارگذاری میکند بررسی میکند تا ببیند آیا مسیر آن با /vendor
شروع میشود یا خیر، آن را با علامتی تگ میکند که دستورات آن باید در زمینه vendor init اجرا شوند. هر ورودی init با یک بولین حاشیه نویسی می شود که مشخص می کند آیا این دستور باید در زیرفرایند init فروشنده اجرا شود یا خیر:
- اکثر دستوراتی که به سیستم فایل دسترسی دارند برای اجرا در زیرفرآیند init vendor مشروح می شوند و بنابراین در معرض SEPolicy ابتدایی فروشنده قرار می گیرند.
- اکثر دستوراتی که روی حالت اولیه داخلی تأثیر میگذارند (مثلاً راهاندازی و توقف سرویسها) در فرآیند شروع عادی اجرا میشوند. این دستورات آگاه می شوند که یک اسکریپت فروشنده آنها را فرا می خواند تا مدیریت مجوزهای غیر SELinux خود را انجام دهند.
حلقه پردازش اصلی init حاوی یک بررسی است که اگر دستوری برای اجرا در زیرفرایند فروشنده مشروح شده باشد و از یک اسکریپت فروشنده نشات گرفته باشد، آن فرمان از طریق ارتباط بین فرآیندی (IPC) به زیرفرایند init فروشنده ارسال می شود که دستور را اجرا می کند. و نتیجه را به init برمی گرداند.
با استفاده از Vendor Init
Vendor init به طور پیشفرض فعال است و محدودیتهای آن برای همه اسکریپتهای init موجود در پارتیشن /vendor
اعمال میشود. Init فروشنده باید برای فروشندگانی که اسکریپتهایشان قبلاً فقط به فایلهای سیستم، ویژگیها و غیره دسترسی ندارند، شفاف باشد.
با این حال، اگر دستورات در یک اسکریپت فروشنده معین، محدودیتهای اولیه فروشنده را نقض کنند، دستورات با شکست مواجه میشوند. دستورات ناموفق دارای یک خط در لاگ هسته (قابل مشاهده با dmesg) از init هستند که نشان دهنده شکست است. ممیزی SELinux همراه با هر دستور ناموفقی است که به دلیل خط مشی SELinux شکست خورده است. مثالی از خرابی از جمله ممیزی SELinux:
type=1400 audit(1511821362.996:9): avc: denied { search } for pid=540 comm="init" name="nfc" dev="sda45" ino=1310721 scontext=u:r:vendor_init:s0 tcontext=u:object_r:nfc_data_file:s0 tclass=dir permissive=0 init: Command 'write /data/nfc/bad_file_access 1234' action=boot (/vendor/etc/init/hw/init.walleye.rc:422) took 2ms and failed: Unable to write to file '/data/nfc/bad_file_access': open() failed: Permission denied
اگر دستوری با شکست مواجه شود، دو گزینه وجود دارد:
- اگر فرمان به دلیل محدودیت مورد نظر ناموفق باشد (مثلاً اگر دستور به یک فایل یا ویژگی سیستم دسترسی داشته باشد)، دستور باید دوباره به روشی سهگانه اجرا شود و فقط از طریق رابطهای پایدار عبور کند. قوانین اجازه ندهید از افزودن مجوزها برای دسترسی به فایلهای سیستمی که بخشی از ABI پایدار سیستم فروشنده نیستند جلوگیری میکند.
- اگر برچسب SELinux جدید است و قبلاً مجوزهایی در سیستم
vendor_init.te
اعطا نشده است یا مجوزهایی از طریق قوانین neverallow مستثنی نشده است، ممکن است برچسب جدید درvendor_init.te
خاص دستگاه مجوز داشته باشد.
برای دستگاههایی که قبل از Android 9 راهاندازی میشوند، قوانین neverallows ممکن است با افزودن ویژگی type data_between_core_and_vendor_violators
به فایل vendor_init.te
خاص دستگاه دور زده شوند.
مکان های کد
بخش عمده منطق IPC init فروشنده در system/core/init/subcontext.cpp است.
جدول دستورات در کلاس BuiltinFunctionMap
در system/core/init/builtins.cpp است و شامل حاشیه نویسی هایی است که نشان می دهد آیا دستور باید در زیرفرایند init فروشنده اجرا شود یا خیر.
SEPolicy برای فروشنده init در دایرکتوری های خصوصی ( system/sepolicy/private/vendor_init.te ) و عمومی ( system/sepolicy/public/vendor_init.te ) در system/sepolicy تقسیم می شود.