לתהליך init יש הרשאות כמעט בלתי מוגבלות, והוא משתמש בסקריפטים של קלט ממחיצות המערכת והספק כדי לאתחל את המערכת במהלך תהליך האתחול. הגישה הזו יוצרת פרצה גדולה בהפרדה בין המערכת לספק ב-Treble, כי סקריפטים של ספקים עשויים להנחות את init לגשת לקבצים, למאפיינים וכו' שלא מהווים חלק מממשק הבינארי של האפליקציה (ABI) של המערכת היציבה של הספק.
התכונה Vendor init נועדה לסגור את הפער הזה באמצעות דומיין נפרד של Linux (SELinux) עם אבטחה משופרת vendor_init
להרצת פקודות שנמצאות ב-/vendor
עם הרשאות ספציפיות לספק.
מנגנון
תהליך האתחול של הספק יוצר תהליך משנה של האתחול בשלב מוקדם בתהליך האתחול עם הקשר SELinux u:r:vendor_init:s0
. להקשר הזה של SELinux יש הרבה פחות הרשאות מהקשר של init שמוגדר כברירת מחדל, והגישה שלו מוגבלת לקבצים, למאפיינים וכו' שהם ספציפיים לספק או שהם חלק מ-ABI יציב של ספק המערכת.
הפונקציה Init בודקת כל סקריפט שהיא טוענת כדי לראות אם הנתיב שלו מתחיל ב-
/vendor
. אם כן, היא מתייגת אותו בציון שהפקודות שלו צריכות לפעול בהקשר של ספק ה-Init. כל פקודת init מובנית מסומנת בערך בוליאני שמציין אם הפקודה חייבת לפעול בתהליך המשנה של init של הספק:
- רוב הפקודות שמאפשרות גישה למערכת הקבצים מסומנות להרצה בתהליך המשנה של ספק init, ולכן הן כפופות ל-SEPolicy של ספק init.
- רוב הפקודות שמשפיעות על מצב ההפעלה הפנימי (לדוגמה, הפעלה והפסקה של שירותים) מופעלות בתהליך ההפעלה הרגיל. הפקודות האלה מודעות לכך שסקריפט של ספק קורא להן כדי לבצע טיפול משלהן בהרשאות שאינן של SELinux.
לולאת העיבוד הראשית של init כוללת בדיקה שאם פקודה מסומנת להפעלה בתהליך המשנה של הספק ומקורה בסקריפט של הספק, הפקודה הזו נשלחת דרך תקשורת בין תהליכים (IPC) לתהליך המשנה של init של הספק, שמפעיל את הפקודה ושולח את התוצאה בחזרה ל-init.
שימוש בהפעלה של ספק
ההגדרה Vendor init מופעלת כברירת מחדל, וההגבלות שלה חלות על כל סקריפטים של init שנמצאים במחיצה /vendor
. האתחול של הספק צריך להיות שקוף לספקים שהסקריפטים שלהם כבר לא ניגשים לקבצים, למאפיינים וכו' של המערכת בלבד.
עם זאת, אם פקודות בסקריפט של ספק מסוים מפרות את ההגבלות על הפעלת הספק, הפקודות ייכשלו. לפקודות שנכשלות יש שורה ביומן של ליבת המערכת (אפשר לראות אותה באמצעות 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
אם פקודה נכשלת, יש שתי אפשרויות:
- אם הפקודה נכשלת בגלל הגבלה מכוונת (למשל אם הפקודה ניגשת לקובץ מערכת או למאפיין), צריך להטמיע מחדש את הפקודה באופן שתואם ל-Treble, כלומר רק דרך ממשקים יציבים. כללי Neverallow מונעים הוספת הרשאות גישה לקבצי מערכת שלא נכללים ב-ABI היציב של ספק המערכת.
- אם תווית SELinux חדשה ולא הוענקו לה כבר הרשאות במערכת
vendor_init.te
או הרשאות מוחרגות באמצעות כללי neverallow, יכול להיות שיוענקו לתווית החדשה הרשאות ב-vendor_init.te
הספציפי למכשיר.
במכשירים שהושקו לפני Android 9, אפשר לעקוף את כללי neverallows על ידי הוספת data_between_core_and_vendor_violators
typeattribute לקובץ vendor_init.te
הספציפי למכשיר.
מיקומי קוד
רוב הלוגיקה של ה-IPC של ספק ההגדרה נמצאת ב-system/core/init/subcontext.cpp.
טבלת הפקודות נמצאת במחלקה BuiltinFunctionMap
ב-system/core/init/builtins.cpp והיא כוללת הערות שמציינות אם הפקודה צריכה לפעול בתהליך המשנה vendor
init.
מדיניות ה-SE עבור vendor init מחולקת בין הספריות הפרטיות (system/sepolicy/private/vendor_init.te) והציבוריות (system/sepolicy/public/vendor_init.te) ב-system/sepolicy.