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

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

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

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

קובצי מקור

הלוגיקה של בניית 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: הגדרות מדיניות הליבה של Android SELinux, כולל קבצי מדיניות והקשרים. הלוגיקה העיקרית של בניית sepolicy נמצאת גם כאן (system/sepolicy/Android.mk).

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

‫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 במכשיר:

בתמונה הזו מוצגת הלוגיקה של בניית 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.mk.

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

מיקום הכלה
system/sepolicy/public ‫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's sepolicy API
SYSTEM_EXT_PRIVATE_SEPOLICY_DIRS (Android מגרסה 11 ואילך) פרטי הטמעה של System_ext (ספקים יכולים להתעלם)
PRODUCT_PUBLIC_SEPOLICY_DIRS (Android מגרסה 11 ואילך) Product's sepolicy API
PRODUCT_PRIVATE_SEPOLICY_DIRS (Android מגרסה 11 ואילך) פרטי הטמעה של מוצרים (ספקים יכולים להתעלם)

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

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

מדיניות ציבורית של SELinux בפלטפורמה

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

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

מדיניות פרטית של SELinux בפלטפורמה

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

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

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

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

system_ext ו-product sepolicy

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

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

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

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

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

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

דוגמה להוספת קובץ מיפוי של מחיצת מוצרים של מכשיר 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.