יצירת מדיניות 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 צריך לטעון את המחיצות system ואת מחיצות הספק מוקדם יותר כדי שיוכל לקרוא קובצי SELinux מהמחיצות האלה ולמזג אותם עם קובצי SELinux ליבה בספרייה system (לפני הטעינה שלהם לליבה).

קובצי מקור

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

  • external/selinux: פרויקט SELinux חיצוני, שמשמש לבניית כלי שורת פקודה של HOST כדי לקמפל את מדיניות SELinux והתוויות.
    • external/selinux/libselinux: מערכת Android משתמשת רק בחלק מהפרויקט החיצוני libselinux, וגם בכמה התאמות אישיות שספציפיות ל-Android. פרטים נוספים זמינים במאמר בנושא external/selinux/README.android.
    • external/selinux/libsepol:
      • chkcon: Determine if a security context is valid for a given binary policy (host executable).
      • 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 זמינים במאמר בנושא קבצי מפתחות.

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

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

תהליך הפיתוח ב-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 SELinux

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

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

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

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

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

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