יצירת מדיניות SELinux

בדף הזה מוסבר איך בנויה מדיניות SELinux. מדיניות SELinux מבוססת על שילוב של מדיניות ליבה של AOSP (פלטפורמה) ומדיניות ספציפית למכשיר (ספק). תהליך בניית מדיניות SELinux ב-Android מגרסה 4.4 עד גרסה 7.0 מיזג את כל חלקי מדיניות SELinux ואז יצר קבצים מונוליטיים בספריית הבסיס. המשמעות היא שספקי SoC ויצרני ODM שינו את boot.img (למכשירים שאינם A/B) או את system.img (למכשירי A/B) בכל פעם שהמדיניות השתנתה.

ב-Android מגרסה 8.0 ואילך, המדיניות של הפלטפורמה והספק מובנית בנפרד. ספקי SoC ויצרני ציוד מקורי (OEM) יכולים לעדכן את החלקים שלהם במדיניות, ליצור את התמונות שלהם (כמו vendor.img ו-boot.img), ואז לעדכן את התמונות האלה בלי קשר לעדכוני הפלטפורמה.

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

קובצי מקור

הלוגיקה של בניית SELinux נמצאת בקבצים הבאים:

  • external/selinux: פרויקט SELinux חיצוני, שמשמש לבניית כלי שורת פקודה של HOST כדי לקמפל את מדיניות SELinux והתוויות.
    • external/selinux/libselinux: מערכת Android משתמשת רק בחלק מהפרויקט החיצוני libselinux, וגם בכמה התאמות אישיות שספציפיות ל-Android. פרטים נוספים מופיעים במאמר בנושא external/selinux/README.android.
    • external/selinux/libsepol:
      • chkcon: קובעת אם הקשר אבטחה תקף למדיניות בינארית נתונה (קובץ הפעלה של המארח).
      • libsepol: ספריית SELinux לשינוי מדיניות אבטחה בינארית (ספרייה סטטית/משותפת של המארח, ספרייה סטטית של היעד).
    • external/selinux/checkpolicy: SELinux policy compiler (host executables: checkpolicy, checkmodule, and dispol). Depends on libsepol.
  • system/sepolicy: הגדרות של מדיניות SELinux ב-Android, כולל קבצים של מדיניות והקשרים. הלוגיקה העיקרית של בניית sepolicy נמצאת גם כאן (system/sepolicy/Android.mk).

פרטים נוספים על הקבצים ב-system/sepolicy זמינים במאמר בנושא קבצי מפתחות.

‫Android מגרסה 7.x ומטה

בקטע הזה מוסבר איך מדיניות SELinux בנויה ב-Android מגרסה 7.x ומטה.

תהליך ה-build ל-Android מגרסה 7.x ומטה

מדיניות SELinux נוצרת על ידי שילוב של מדיניות הליבה של AOSP עם התאמות אישיות ספציפיות למכשיר. לאחר מכן, המדיניות המשולבת מועברת לקומפיילר המדיניות ולבודקים שונים. התאמה אישית ספציפית למכשיר מתבצעת באמצעות המשתנה BOARD_SEPOLICY_DIRS שמוגדר בקובץ Boardconfig.mk הספציפי למכשיר. משתנה הבנייה הגלובלי הזה מכיל רשימה של ספריות שמציינות את הסדר שבו יתבצע החיפוש אחר קובצי מדיניות נוספים.

לדוגמה, ספק SoC ו-ODM יכולים להוסיף כל אחד ספרייה, אחת להגדרות ספציפיות ל-SoC ואחת להגדרות ספציפיות למכשיר, כדי ליצור את תצורות SELinux הסופיות למכשיר נתון:

  • BOARD_SEPOLICY_DIRS += device/SoC/common/sepolicy
  • BOARD_SEPOLICY_DIRS += device/SoC/DEVICE/sepolicy

התוכן של קובצי file_contexts ב-system/sepolicy וב-BOARD_SEPOLICY_DIRS משורשר כדי ליצור את file_contexts.bin במכשיר:

לוגיקת ה-build של SELinux ל-Android 7.x

איור 1. לוגיקת ה-build של SELinux.

הקובץ sepolicy מורכב מכמה קובצי מקור:

  • הטקסט הפשוט policy.conf נוצר על ידי שרשור של הקבצים security_classes, initial_sids, *.te, genfs_contexts ו-port_contexts, בסדר הזה.
  • לכל קובץ (למשל security_classes), התוכן שלו הוא שרשור של הקבצים עם אותו שם בתיקיות system/sepolicy/ ו-BOARDS_SEPOLICY_DIRS.
  • policy.conf נשלח לקומפיילר SELinux לבדיקת התחביר, ועובר קומפילציה לפורמט בינארי כ-sepolicy במכשיר.

    קובצים שיוצרים את קובץ המדיניות של SELinux
      ל-Android 7.x
    איור 2. קובץ מדיניות SELinux.

קבצים של SELinux

אחרי ההידור, מכשירי Android בגרסה 7.x ומטה מכילים בדרך כלל את הקבצים הבאים שקשורים ל-SELinux:

  • selinux_version
  • sepolicy: פלט בינארי אחרי שמשלבים קובצי מדיניות (כמו security_classes, initial_sids ו-*.te)
  • file_contexts
  • property_contexts
  • seapp_contexts
  • service_contexts
  • system/etc/mac_permissions.xml

פרטים נוספים זמינים במאמר בנושא הטמעה של SELinux.

אתחול SELinux

כשהמערכת מופעלת, SELinux נמצא במצב מתירני (ולא במצב מחייב). תהליך ההפעלה מבצע את המשימות הבאות:

  • טוען sepolicy קבצים מ-ramdisk לתוך הליבה דרך /sys/fs/selinux/load.
  • הפקודה מעבירה את SELinux למצב אכיפה.
  • מריצים את הפקודה re-exec() כדי להחיל את כלל הדומיין של SELinux על עצמו.

כדי לקצר את זמן האתחול, צריך לבצע את התהליך re-exec()init בהקדם האפשרי.

‫Android מגרסה 8.0 ואילך

ב-Android 8.0, מדיניות SELinux מחולקת לרכיבי פלטפורמה וספק כדי לאפשר עדכוני מדיניות עצמאיים של פלטפורמה וספק תוך שמירה על תאימות.

פלטפורמת sepolicy מחולקת לחלקים פרטיים וציבוריים כדי לייצא סוגים ומאפיינים ספציפיים לכותבי מדיניות של ספקים. מובטח שסוגים או מאפיינים ציבוריים של הפלטפורמה יישמרו כממשקי API יציבים לגרסה נתונה של הפלטפורמה. אפשר להבטיח תאימות עם סוגים או מאפיינים ציבוריים קודמים של הפלטפורמה למשך כמה גרסאות באמצעות קובצי מיפוי של הפלטפורמה.

תהליך ה-build ל-Android 8.0

מדיניות SELinux ב-Android 8.0 נוצרת על ידי שילוב של חלקים מ-/system ומ-/vendor. הלוגיקה להגדרה נכונה מפורטת במאמר /platform/system/sepolicy/Android.bp.

המדיניות קיימת במיקומים הבאים:

מיקום הכלה
system/sepolicy/public Platform sepolicy API
system/sepolicy/private פרטי ההטמעה בפלטפורמה (ספקים יכולים להתעלם)
system/sepolicy/vendor קבצים של מדיניות והקשר שספקים יכולים להשתמש בהם (הספקים יכולים להתעלם מהם)
BOARD_SEPOLICY_DIRS Vendor sepolicy
BOARD_ODM_SEPOLICY_DIRS (Android מגרסה 9 ואילך) ODM sepolicy
SYSTEM_EXT_PUBLIC_SEPOLICY_DIRS (Android מגרסה 11 ואילך) system_ext sepolicy API
SYSTEM_EXT_PRIVATE_SEPOLICY_DIRS (Android מגרסה 11 ואילך) system_ext פרטי הטמעה (הספקים יכולים להתעלם)
PRODUCT_PUBLIC_SEPOLICY_DIRS (Android מגרסה 11 ואילך) Product sepolicy API
PRODUCT_PRIVATE_SEPOLICY_DIRS (Android מגרסה 11 ואילך) פרטי הטמעה של מוצרים (ספקים יכולים להתעלם)

מערכת ה-Build לוקחת את המדיניות הזו ומפיקה רכיבי מדיניות של system,‏ system_ext,‏ product,‏ vendor ו-odm במחיצה המתאימה. איך פותרים את הבעיה:

  1. המרת כללי המדיניות לפורמט של SELinux Common Intermediate Language ‏ (CIL), באופן ספציפי:
    • מדיניות הפלטפורמה הציבורית (system, system_ext, product)
    • מדיניות משולבת פרטית וציבורית
    • מדיניות ציבורית, מדיניות ספקים ומדיניות BOARD_SEPOLICY_DIRS
  2. הגרסה של המדיניות שסופקה על ידי הציבור כחלק ממדיניות הספק. משתמשים במדיניות ה-CIL הציבורית שנוצרה כדי להגדיר את המדיניות המשולבת הציבורית והספציפית לספק BOARD_SEPOLICY_DIRS, ולציין אילו חלקים צריכים להפוך למאפיינים שמקושרים למדיניות הפלטפורמה.
  3. יוצרים קובץ מיפוי שמקשר בין חלקי הפלטפורמה והספק. בתחילה, המדיניות הזו מקשרת רק בין הסוגים ממדיניות הפרטיות לבין המאפיינים התואמים במדיניות הספק. בהמשך, היא גם מספקת את הבסיס לקובץ שמתעדכן בגרסאות עתידיות של הפלטפורמה, וכך מאפשרת תאימות לטירגוט של מדיניות הספק בגרסה הזו של הפלטפורמה.
  4. שילוב של קובצי מדיניות (תיאור של פתרונות במכשיר ופתרונות שעברו קומפילציה מראש).
    1. שילוב של מיפוי, פלטפורמה ומדיניות ספקים.
    2. קומפילציה של קובץ מדיניות בינארי של פלט.

מדיניות ציבורית של Platform sepolicy

מדיניות ה-SELinux הציבורית של הפלטפורמה כוללת את כל מה שמוגדר ב- system/sepolicy/public. הפלטפורמה יכולה להניח שהסוגים והמאפיינים שמוגדרים במסגרת מדיניות ציבורית הם ממשקי API יציבים לגרסה נתונה של הפלטפורמה. החלק הזה הוא חלק ממדיניות ה-SEPolicy שמיוצאת על ידי הפלטפורמה שבה מפתחי מדיניות של ספקים (כלומר, מכשירים) יכולים לכתוב מדיניות נוספת ספציפית למכשיר.

הסוגים הם בעלי גרסאות בהתאם לגרסת המדיניות שקבצי הספק נכתבים לפיה, שמוגדרת על ידי משתנה ה-build‏ PLATFORM_SEPOLICY_VERSION. לאחר מכן, המדיניות הציבורית עם ניהול הגרסאות נכללת במדיניות הספק (בגרסה המקורית שלה) ובמדיניות הפלטפורמה. לכן, המדיניות הסופית כוללת את מדיניות הפלטפורמה הפרטית, את מדיניות ה-SELinux הציבורית הנוכחית של הפלטפורמה, את המדיניות הספציפית למכשיר ואת המדיניות הציבורית עם הגרסה שתואמת לגרסת הפלטפורמה שלפיה נכתבה מדיניות המכשיר.

מדיניות פרטית של אבטחת מידע (SEPolicy) בפלטפורמה

מדיניות הפרטיות של הפלטפורמה כוללת את כל מה שמוגדר בקטע /system/sepolicy/private. החלק הזה של המדיניות כולל סוגים, הרשאות ומאפיינים שנדרשים לפונקציונליות של הפלטפורמה. הנתונים האלה לא מיוצאים לספקי המדיניות למכשירים ולכותבי המדיניות. כותבי מדיניות שאינם פלטפורמה לא יכולים לכתוב את הרחבות המדיניות שלהם על סמך סוגים, מאפיינים וכללים שהוגדרו במדיניות הפרטית של הפלטפורמה. בנוסף, יכול להיות שיהיה אפשר לשנות את הכללים האלה, או שהם ייעלמו כחלק מעדכון של המסגרת בלבד.

מיפוי פרטי של פלטפורמה

מיפוי הפרטיות של הפלטפורמה כולל הצהרות מדיניות שממפות את המאפיינים שנחשפים במדיניות הציבורית של הפלטפורמה בגרסאות קודמות של הפלטפורמה לסוגים הקונקרטיים שמשמשים במדיניות הציבורית הנוכחית של הפלטפורמה. כך אפשר להבטיח שמדיניות הספק שנכתבה על סמך מאפיינים ציבוריים של הפלטפורמה מגרסאות קודמות של מדיניות האבטחה של הפלטפורמה (SELinux) תמשיך לפעול. הגרסאות מבוססות על PLATFORM_SEPOLICY_VERSIONמשתנה ה-build שמוגדר ב-AOSP לגרסת פלטפורמה נתונה. קיים קובץ מיפוי נפרד לכל גרסה קודמת של הפלטפורמה, שממנה הפלטפורמה הזו צפויה לקבל מדיניות של ספקים. פרטים נוספים מופיעים בקטע תאימות למדיניות.

‫Android מגרסה 11 ואילך

בקטע הזה מוסבר איך מדיניות SELinux בנויה ב-Android מגרסה 11 ואילך.

system_ext ו-product sepolicy

ב-Android 11, נוספו מדיניות system_ext ומדיניות product. בדומה למדיניות sepolicy של הפלטפורמה, המדיניות system_ext והמדיניות product מחולקות למדיניות ציבורית ולמדיניות פרטית.

מדיניות ציבורית מיוצאת לספק. הסוגים והמאפיינים הופכים ל-API יציב, ומדיניות הספק יכולה להתייחס לסוגים ולמאפיינים במדיניות הציבורית. הסוגים הם עם מספור גרסאות לפי PLATFORM_SEPOLICY_VERSION, ומדיניות הספק כוללת את המדיניות עם מספור הגרסאות. המדיניות המקורית כלולה בכל מחיצה של system_ext ו-product.

מדיניות הפרטיות מכילה סוגים, הרשאות ומאפיינים של system_ext בלבד ושל product בלבד שנדרשים לפונקציונליות של חלוקת system_ext ו-product. מדיניות הפרטיות לא גלויה לספק, מה שאומר שהכללים האלה הם פנימיים ומותר לשנות אותם.

מיפוי של system_ext ומוצרים

למשתמשים system_ext ו-product יש הרשאה לייצא את הסוגים הציבוריים שמוגדרים להם לספק. עם זאת, כל שותף אחראי לשמור על תאימות. לצורך תאימות, שותפים יכולים לספק קובצי מיפוי משלהם שממפים את המאפיינים עם הגרסאות של גרסאות קודמות לסוגים קונקרטיים שמשמשים במדיניות ה-sepolicy הציבורית הנוכחית:

  • כדי להתקין קובץ מיפוי עבור system_ext, מעבירים קובץ CIL שמכיל את פרטי המיפוי הרצויים אל {SYSTEM_EXT_PRIVATE_SEPOLICY_DIRS}/compat/{ver}/{ver}.cil, ואז מוסיפים את system_ext_{ver}.cil אל PRODUCT_PACKAGES.
  • כדי להתקין קובץ מיפוי עבור product, מעבירים קובץ CIL שמכיל את פרטי המיפוי הרצויים אל {PRODUCT_PRIVATE_SEPOLICY_DIRS}/compat/{ver}/{ver}.cil, ואז מוסיפים את product_{ver}.cil אל PRODUCT_PACKAGES.

בדוגמה מוסיפים קובץ מיפוי של מחיצת product במכשיר Redbull.

מדיניות SELinux שעברה קומפילציה מראש

לפני שמערכת init מפעילה את SELinux, היא אוספת את כל קובצי ה-CIL ממחיצות (system, system_ext, product, vendor ו-odm) ומקמפלת אותם למדיניות בינארית, הפורמט שאפשר לטעון לליבת המערכת.init הקומפילציה אורכת זמן (בדרך כלל שנייה אחת או שתיים), ולכן קובצי ה-CIL עוברים קומפילציה מראש בזמן ה-build ומוצבים ב-/vendor/etc/selinux/precompiled_sepolicy או ב-/odm/etc/selinux/precompiled_sepolicy, יחד עם גיבובי ה-SHA256 של קובצי ה-CIL של הקלט. בזמן הריצה, init בודק אם קובץ המדיניות עודכן על ידי השוואת הגיבובים. אם לא חל שינוי, הפונקציה init טוענת את המדיניות שעברה קומפילציה מראש. אם לא, init יבצע קומפילציה תוך כדי תנועה וישתמש בה במקום בקובץ שעבר קומפילציה מראש.

באופן ספציפי יותר, המדיניות שעברה קומפילציה מראש נמצאת בשימוש אם כל התנאים הבאים מתקיימים. כאן, {partition} מייצג את המחיצה שבה קיימת המדיניות שעברה קומפילציה מראש: vendor או odm.

  • הערכים /system/etc/selinux/plat_sepolicy_and_mapping.sha256 ו-/{partition}/etc/selinux/precompiled_sepolicy.plat_sepolicy_and_mapping.sha256 זהים וקיימים.
  • המינויים של /system_ext/etc/selinux/system_ext_sepolicy_and_mapping.sha256 ו-/{partition}/etc/selinux/precompiled_sepolicy.system_ext_sepolicy_and_mapping.sha256 לא קיימים. או ששניהם קיימים וזהים.
  • המינויים של /product/etc/selinux/product_sepolicy_and_mapping.sha256 ו-/{partition}/etc/selinux/precompiled_sepolicy.product_sepolicy_and_mapping.sha256 לא קיימים. או ששניהם קיימים וזהים.

אם יש הבדל בין הערכים, init חוזרת לנתיב ההידור במכשיר. לפרטים נוספים, ראו system/core/init/selinux.cpp.