Vendor init

לתהליך 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, תוך שימוש בממשקי API יציבים בלבד. כללי Neverallow מונעים הוספת הרשאות גישה לקבצי מערכת שלא מהווים חלק מ-ABI יציב של ספק המערכת.
  • אם תווית SELinux חדשה ולא הוענקו לה הרשאות במערכת vendor_init.te או שהיא לא נכללת בהרשאות שמוחרגות באמצעות כללי neverallow, יכול להיות שיוענקו לה הרשאות ב-vendor_init.te הספציפי למכשיר.

במכשירים שהושקו לפני Android 9, אפשר לעקוף את כללי neverallows על ידי הוספת מאפיין הסוג data_between_core_and_vendor_violators לקובץ vendor_init.te הספציפי למכשיר.

מיקומי קוד

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

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

מדיניות ה-SE עבור init של ספקים מפוצלת בין הספריות הפרטיות (system/sepolicy/private/vendor_init.te) והציבוריות (system/sepolicy/public/vendor_init.te) ב-system/sepolicy.