Vendor init

לתהליך ה-init יש הרשאות כמעט בלתי מוגבלות, והוא משתמש בסקריפטים של קלט גם מהמחיצות של המערכת וגם מהמחיצות של הספק כדי לאתחל את המערכת במהלך תהליך האתחול. הגישה הזו יוצרת חור גדול בחלוקה של Treble למערכת ולספק, כי סקריפטים של ספקים עשויים להורות ל-init לגשת לקבצים, למאפיינים וכו' שלא נכללים בממשק הבינארי היציב של האפליקציה (ABI) של המערכת והספק.

Vendor init נועד לסגור את החור הזה באמצעות דומיין נפרד של Linux עם אבטחה משופרת (SELinux)‏ vendor_init, כדי להריץ פקודות שנמצאות ב-/vendor עם הרשאות ספציפיות לספק.

מנגנון

Vendor init יוצר תהליך משנה של init בשלב מוקדם בתהליך האתחול, עם ההקשר של SELinux‏ u:r:vendor_init:s0. להקשר SELinux הזה יש הרבה פחות הרשאות בהשוואה להקשר init שמוגדר כברירת מחדל, והגישה שלו מוגבלת לקבצים, למאפיינים וכו' שספציפיים לספק או שהם חלק מ-ABI היציב של ספק המערכת.

‏Init בודקת כל סקריפט שהיא טוענת כדי לראות אם הנתיב שלו מתחיל ב-/vendor. אם כן, היא מסמנת אותו עם אינדיקציה לכך שצריך להריץ את הפקודות שלו בהקשר של init של הספק. כל פונקציה מובנית של init מסומנת ב-annotation של ערך בוליאני שמציין אם צריך להריץ את הפקודה בתהליך המשנה של init של הספק או לא:

  • רוב הפקודות שמקבלות גישה למערכת הקבצים מסומנות לפעול בתהליך המשנה של init של הספק, ולכן הן כפופות ל-SEPolicy של init של הספק.
  • רוב הפקודות שמשפיעות על מצב init הפנימי (למשל, הפעלה והפסקה של שירותים) פועלות בתהליך init הרגיל. הפקודות האלה יודעות שסקריפט של ספק קורא להן כדי לבצע טיפול משלה בהרשאות שאינן של SELinux.

לולאת העיבוד הראשית של init מכילה בדיקה שאם צוין בפקודה שהיא צריכה לפעול בתהליך המשנה של הספק, והיא מגיעה מסקריפט של הספק, הפקודה נשלחת באמצעות תקשורת בין תהליכים (IPC) לתהליך המשנה של init של הספק, שמריץ את הפקודה ושולח את התוצאה חזרה אל init.

שימוש ב-vendor 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 לקובץ vendor_init.te הספציפי למכשיר.

מיקומי קוד

רוב הלוגיקה של ה-IPC של init של הספק נמצאת בקובץ system/core/init/subcontext.cpp.

טבלת הפקודות נמצאת בכיתה BuiltinFunctionMap בקובץ system/core/init/builtins.cpp, והיא כוללת הערות שמציינות אם הפקודה צריכה לפעול בתהליך המשנה של init של הספק.

ה-SEPolicy ל-vendor init מחולק בין הספריות הפרטיות (system/sepolicy/private/vendor_init.te) לבין הספריות הציבוריות (system/sepolicy/public/vendor_init.te) ב-system/sepolicy.