תאימות למדיניות

במאמר הזה מתואר איך מערכת Android מטפלת בבעיות תאימות למדיניות עם OTA בפלטפורמה, שבה ההגדרות של SELinux בפלטפורמה החדשות עשויות להיות שונות מהספק הישן הגדרות SELinux.

תכנון מדיניות SELinux שמבוסס על טרבל מביא בחשבון הבחנה בינארית בין מדיניות platform למדיניות ספק; הסכמה הופכת מורכבים יותר אם מחיצות של ספקים יוצרות יחסי תלות, כמו platform < vendor < oem

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

  • במסגרת ניהול גרסאות, המדיניות שמיוצאת לפלטפורמה-ציבורית תיכתב כך: מאפיינים.
  • כדי להקל על כתיבת המדיניות, הסוגים המיוצאים יומרו מאפיינים כחלק מתהליך ה-build של המדיניות. גלוי לכולם יכול להיות שנשתמש בהם גם באופן ישיר, בהחלטות לגבי תוויות שסופקו על ידי הספק קובצי הקשרים.

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

בעלות ותיוג של אובייקטים

במהלך התאמה אישית של המדיניות ב-Android מגרסה 8.0 ואילך, צריך להגדיר בעלות בבירור עבור כל אובייקט, כדי לשמור בנפרד על מדיניות הפלטפורמה והספק. לדוגמה, אם תוויות הספק /dev/foo, הפלטפורמה, ואז תוויות /dev/foo ב-OTA הבא, תהיה התנהגות לא מוגדרת. עבור SELinux, שמתבטא בהתנגשות בין תוויות. צומת המכשיר יכול לכלול רק תווית אחת שמפנה לתווית האחרונה שהוחלה. כתוצאה מכך:

  • תהליכים שצריכים גישה לתווית שהוחלה עליהם בהצלחה יאבדו את הגישה למשאב.
  • תהליכים שמקבלים גישה לקובץ עלולים לא לפעול בגלל שגיאה הצומת של המכשיר נוצר.

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

בנוסף להתנגשויות של תוויות, שמות של סוג/מאפיינים SELinux עשויים להתנגש. התנגשות בין שמות של סוג או מאפיין תמיד תוביל לשגיאת מהדר של מדיניות.

ריווח שמות של סוג/מאפיינים

ב-SELinux אי אפשר להשתמש בהצהרות מרובות מאותו סוג או מאותו מאפיין. מדיניות עם הצהרות כפולות, לא יהיה אוסף. כדי להימנע משימוש בהקלדה התנגשויות בין שמות מאפיינים, כל הצהרות הספקים צריכות להיות במרחב שמות החל מ-vendor_.

type foo, domain; → type vendor_foo, domain;

מאפיין מערכת וגם תהליך הבעלות על תוויות

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

סוג הנכס תחיליות מקובלות
מאפייני בקרה ctl.vendor.
ctl.start$vendor.
ctl.stop$vendor.
init.svc.vendor.
ניתן לכתיבה vendor.
קריאה-בלבד ro.vendor.
ro.boot.
ro.hardware.
מתמיד persist.vendor.

ספקים יכולים להמשיך להשתמש ב-ro.boot.* (שמקורו בליבה (kernel) cmdline) ו-ro.hardware.* (מאפיין ברור שקשור לחומרה).

כל שירותי הספק בקובצי rc התחלתיים צריכים להכיל vendor. לשירותים באתחול קובצי rc של מחיצות שהן לא מערכת. כללים דומים הם הוחלו על תוויות SELinux עבור מאפייני הספק (vendor_ של מאפייני הספק).

בעלות על קובץ

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

מערכת (/מערכת)

רק תמונת המערכת חייבת לספק תוויות לרכיבי /system עד file_contexts, service_contexts וכו'. אם תוויות לרכיבי /system נוספו במדיניות /vendor, יכול להיות שלא תוכלו לעדכן OTA רק באמצעות framework.

ספק (/ספק)

מדיניות AOSP SELinux כבר מציינת חלקים ממחיצה vendor הפלטפורמה מקיימת אינטראקציה איתן, וכך מאפשרת לכתוב כללי SELinux לפלטפורמה כדי שיוכלו לדבר ו/או לגשת לחלקים של vendor מחיצה. לדוגמה:

נתיב אחד (/vendor) תווית של הפלטפורמה תהליכי פלטפורמה בהתאם לתווית
/vendor(/.*)? vendor_file כל לקוחות HAL ב-framework, ueventd וכו'.
/vendor/framework(/.*)? vendor_framework_file dex2oat, appdomain וכו'
/vendor/app(/.*)? vendor_app_file dex2oat, installd, idmap וכו'
/vendor/overlay(/.*) vendor_overlay_file system_server, zygote, idmap וכו'

כתוצאה מכך, יש לפעול לפי כללים מסוימים (לאכוף אותם באמצעות neverallows) כשמוסיפים תוויות לקבצים נוספים בקובץ vendor מחיצה:

  • vendor_file חייב להיות תווית ברירת המחדל לכל הקבצים ב- מחיצה vendor. לפי מדיניות הפלטפורמה, צריך את זה כדי הטמעת פרוטוקול HAL של העברה.
  • כל ערכי exec_types החדשים נוספו במחיצה vendor דרך SEPolicy של הספק, חייב להיות מאפיין vendor_file_type. הזה נאכף באמצעות איסורים.
  • כדי למנוע התנגשויות עם עדכונים עתידיים של פלטפורמה או framework, מומלץ לא להוסיף תוויות קבצים אחרים מלבד exec_types במחיצה vendor.
  • לכל יחסי התלות של ספריות עבור HAL של תהליך שמזוהה על ידי AOSP צריך להיות מתויג בתור same_process_hal_file.

Procfs (/proc)

ניתן לתייג קבצים בתיקייה /proc באמצעות genfscon בלבד התיוג. ב-Android 7.0, גם פלטפורמה וספק המדיניות משתמשת ב-genfscon כדי להוסיף תוויות לקבצים ב-procfs.

המלצה: רק תוויות של מדיניות הפלטפורמה /proc. אם ל-vendor תהליכים נדרשת גישה לקבצים ב-/proc מתויגות כרגע בתווית ברירת המחדל (proc), מדיניות הספק לא צריך לתייג אותם במפורש, אלא להשתמש במקום זאת סוג proc כדי להוסיף כללים לדומיינים של ספקים. זה מאפשר לפלטפורמה עדכונים כדי להתאים לממשקי ליבה עתידיים שנחשפו דרך procfs ותייגו אותם במפורש לפי הצורך.

ניפוי באגים (/sys/kernel/debug)

אפשר להוסיף תווית ל-Debugfs גם ב-file_contexts וגם genfscon. מ-Android 7.0 עד Android 10, גם תווית הפלטפורמה וגם תווית הספק debugfs

ב-Android 11, לא ניתן להשתמש ב-debugfs מתבצעת גישה או טעינה למכשירים בסביבת הייצור. יצרני מכשירים צריכים הסרה של debugfs.

Tracefs (/sys/kernel/debug/tracing)

אפשר להוסיף תווית ל-Tracefs גם ב-file_contexts וגם genfscon. ב-Android 7.0, רק תוויות הפלטפורמה tracefs

המלצה: רק פלטפורמה יכולה להוסיף תווית tracefs.

Sysfs (/sys)

יכול להיות שקבצים בתיקייה /sys יתויגו באמצעות המאפיינים file_contexts ו-genfscon. ב-Android 7.0, השימוש בפלטפורמה וגם בספק file_contexts ו-genfscon כדי להוסיף תוויות לקבצים ב sysfs.

המלצה: יכול להיות שהפלטפורמה תתייג את התווית sysfs צמתים שלא ספציפיים למכשיר. אחרת, רק הספק יכול להוסיף תוויות לקבצים.

tmpfs (/dev)

יכול להיות שקבצים בתיקייה /dev יתויגו ב-file_contexts. לחשבון Android 7.0, כאן מופיעים קובצי תוויות של הפלטפורמה והספק.

המלצה: הספק יכול להוסיף תווית רק לקבצים שנמצאים /dev/vendor (למשל, /dev/vendor/foo, /dev/vendor/socket/bar).

Rootfs (/)

יכול להיות שקבצים בתיקייה / יתויגו ב-file_contexts. ב-Android 7.0, כאן מופיעים קובצי תוויות של הפלטפורמה והספק.

המלצה: רק המערכת יכולה להוסיף תוויות לקבצים שנמצאים ב-/.

נתונים (/נתונים)

הנתונים מתויגים באמצעות שילוב של file_contexts ו- seapp_contexts.

המלצה: אסור להוסיף תוויות לספקים מחוץ לחברה /data/vendor. רק הפלטפורמה יכולה להוסיף תוויות לחלקים אחרים /data

מאפייני תאימות

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

המדיניות מנוסחת בעיקר במונחים קיימים:

allow source_type target_type:target_class permission(s);

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

File_contexts:
/sys/A   u:object_r:sysfs:s0
Platform: allow p_domain sysfs:class perm;
Vendor: allow v_domain sysfs:class perm;

אפשר לשנות ל:

File_contexts:
/sys/A   u:object_r:sysfs_A:s0

מדיניות הספקים לא תשתנה, אבל v_domain תאבד את הגישה בגלל היעדר מדיניות בנוגע למכשיר sysfs_A החדש מהסוג הזה.

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

הגדרת מדיניות ציבורית כמאפיינים בעלי גרסאות עומדת בדרישות של שתי סעיפי מדיניות יעדי תאימות:

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

יכולת כתבי המדיניות

כדי לעמוד במטרה שלא נדרש ידע לגבי שינויים מסוימים בגרסאות של ו-Android 8.0 כולל מיפוי בין פלטפורמה ציבורית עקרונות המדיניות והמאפיינים שלהם. הסוג foo ממופה למאפיין foo_vN, כאשר N הוא גרסה מטורגטת. vN תואם ל- משתנה build PLATFORM_SEPOLICY_VERSION בפורמט MM.NN, כאשר MM תואם למספר ה-SDK של הפלטפורמה ו-NN היא גרסה ספציפית למדיניות בנושא מדיניות.

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

מדיניות ציבורית של פלטפורמה שמיוצאת כ-allow source_foo target_bar:class perm; נכללת במדיניות הספק. במהלך compilation (שכולל את גרסה תואמת) היא עוברת טרנספורמציה למדיניות שתפנה אל החלק של הספק במכשיר (מוצג בנתוני הביניים שעברו שינוי שפה (CIL)):

 (allow source_foo_vN target_bar_vN (class (perm)))

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

הבדלים במדיניות

יצירה אוטומטית של מאפיינים על ידי הוספה של _vN לסוף מכל סוג לא עושה שום דבר בלי למפות את המאפיינים לסוגים שונים של הגרסה שונים. מערכת Android שומרת על מיפוי בין הגרסאות של המאפיינים מיפוי של סוגים למאפיינים האלה. זה נעשה במיפוי שהוזכר קבצים שמכילים הצהרות כמו (CIL):

(typeattributeset foo_vN (foo))

שדרוגי פלטפורמות

בקטע הבא מתוארים תרחישים של שדרוגים לפלטפורמה.

סוגים זהים

התרחיש הזה מתרחש כשאובייקט לא משנה תוויות בגרסאות של מדיניות. הדבר זהה לסוגי מקור ויעד, וניתן לראות את הנתונים האלה כך /dev/binder, עם התווית binder_device בכל המוצרים גרסאות חדשות. הוא מיוצג במדיניות שעברה שינוי כך:

binder_device_v1 … binder_device_vN

כשמשדרגים מ-v1v2, מדיניות הפלטפורמה חייבת מכילים:

type binder_device; -> (type binder_device) (in CIL)

בקובץ המיפוי v1 (CIL):

(typeattributeset binder_device_v1 (binder_device))

בקובץ המיפוי v2 (CIL):

(typeattributeset binder_device_v2 (binder_device))

במדיניות לספקים בגרסה 1 (CIL):

(typeattribute binder_device_v1)
(allow binder_device_v1 …)

במדיניות לספקים בגרסה 2 (CIL):

(typeattribute binder_device_v2)
(allow binder_device_v2 …)
סוגים חדשים

התרחיש הזה מתרחש כשהפלטפורמה הוסיפה סוג חדש, וזה יכול לקרות כשמוסיפים תכונות חדשות או במהלך הקשחת המדיניות.

  • תכונה חדשה. כשהסוג מתייג לאובייקט שסומן שלא היה קיים בעבר (למשל, תהליך שירות חדש), קוד הספק הייתה אינטראקציה ישירה איתו בעבר, כך שלא קיימת מדיניות תואמת. הגרסה החדשה לסוג המתאים אין מאפיין כך שלא תצטרכו רשומה במיקוד של קובץ המיפוי, .
  • הקשחת מדיניות. כשהסוג מייצג מדיניות הקשחה, מאפיין הסוג החדש חייב לקשר חזרה לשרשרת של מאפיינים שתואמת לדוגמה הקודמת (בדומה לדוגמה הקודמת 'שינוי' /sys/A מ-sysfs עד sysfs_A). הספק הקוד מסתמך על כלל שמאפשר גישה אל sysfs, כדי לכלול את הכלל הזה כמאפיין מהסוג החדש.

כשמשדרגים מ-v1v2, מדיניות הפלטפורמה חייבת מכילים:

type sysfs_A; -> (type sysfs_A) (in CIL)
type sysfs; (type sysfs) (in CIL)

בקובץ המיפוי v1 (CIL):

(typeattributeset sysfs_v1 (sysfs sysfs_A))

בקובץ המיפוי v2 (CIL):

(typeattributeset sysfs_v2 (sysfs))
(typeattributeset sysfs_A_v2 (sysfs_A))

במדיניות לספקים בגרסה 1 (CIL):

(typeattribute sysfs_v1)
(allow … sysfs_v1 …)

במדיניות לספקים בגרסה 2 (CIL):

(typeattribute sysfs_A_v2)
(allow … sysfs_A_v2 …)
(typeattribute sysfs_v2)
(allow … sysfs_v2 …)
סוגים שהוסרו

תרחיש (נדיר) זה מתרחש לאחר הסרת סוג, שיכול לקרות כאשר אובייקט בסיסי:

  • נשאר אבל מקבל תווית אחרת.
  • הוסר על ידי הפלטפורמה.

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

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

(typeattribute sysfs_v1)
(allow … sysfs_v1 …)

דוגמה 1: סוגי כיווץ (הסרת sysfs_A)

כשמשדרגים מ-v1v2, מדיניות הפלטפורמה חייבת מכילים:

type sysfs; (type sysfs) (in CIL)

בקובץ המיפוי v1 (CIL):

(typeattributeset sysfs_v1 (sysfs))
(type sysfs_A) # in case vendors used the sysfs_A label on objects
(typeattributeset sysfs_A_v1 (sysfs sysfs_A))

בקובץ המיפוי v2 (CIL):

(typeattributeset sysfs_v2 (sysfs))

במדיניות לספקים בגרסה 1 (CIL):

(typeattribute sysfs_A_v1)
(allow … sysfs_A_v1 …)
(typeattribute sysfs_v1)
(allow … sysfs_v1 …)

במדיניות לספקים בגרסה 2 (CIL):

(typeattribute sysfs_v2)
(allow … sysfs_v2 …)

דוגמה 2: הסרה מלאה (סוג foo)

כשמשדרגים מ-v1v2, מדיניות הפלטפורמה חייבת מכילים:

# nothing - we got rid of the type

בקובץ המיפוי v1 (CIL):

(type foo) #needed in case vendors used the foo label on objects
(typeattributeset foo_v1 (foo))

בקובץ המיפוי v2 (CIL):

# nothing - get rid of it

במדיניות לספקים בגרסה 1 (CIL):

(typeattribute foo_v1)
(allow foo …)
(typeattribute sysfs_v1)
(allow sysfs_v1 …)

במדיניות לספקים בגרסה 2 (CIL):

(typeattribute sysfs_v2)
(allow sysfs_v2 …)
כיתה או הרשאות חדשות

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

כדי להתיר את כל הדומיינים שניתן היה ליצור או להרחיב בהתאם למדיניות הספק כדי להשתמש במחלקה החדשה ללא הפרעות, מדיניות הפלטפורמה צריכה לכלול דומה ל:

allow {domain -coredomain} *:new_class perm;

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

כיתה/הרשאות הוסרו

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

התאמה אישית של ספק עבור סוגים חדשים/מסומנים מחדש

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

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

שינויים במאפיינים ל-Android 9

במכשירים שמשדרגים ל-Android 9 אפשר להשתמש במאפיינים הבאים, אבל מכשירים כשמשיקים עם Android 9, אסור.

מאפייני ההפרה

מערכת Android 9 כוללת את המאפיינים הבאים שקשורים לדומיין:

  • data_between_core_and_vendor_violators מאפיין לכל הדומיינים שמפרים את הדרישה שלא לשתף קבצים עד נתיב בין vendor ל-coredomains. פלטפורמה ו אסור להשתמש בתהליכי ספק בקבצים בדיסק כדי לתקשר (ABI לא יציב). המלצה:
    • קוד הספק צריך להשתמש ב-/data/vendor.
    • המערכת לא צריכה להשתמש ב-/data/vendor.
  • system_executes_vendor_violators תכונה עבור כל הדומיינים של המערכת (למעט init ו-shell domains) שמפרות את הדרישה לאי-שימוש בקבצים בינאריים של ספקים. ביצוע של בקבצים הבינאריים של הספקים יש API לא יציב. אין להפעיל קבצים בינאריים של ספקים בפלטפורמה ישירות. המלצה:
    • יחסי התלות של פלטפורמה שכאלו בקבצים הבינאריים של ספקים חייבים להיות מאחורי תקן HIDL HAL.

      או

    • coredomains שצריכים גישה לקבצים הבינאריים של הספקים צריכים להיות הועבר למחיצת הספק, וכתוצאה מכך להפסיק להיות coredomain.

מאפיינים לא מהימנים

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

  1. שרתי HwBinder לא מבצעים אימות לקוח כי כרגע HIDL לא חושפת את פרטי UID של המתקשר. גם אם HIDL כן חשף נתונים כאלה, שירותי HwBinder פועלים ברמה נמוכה מזו של אפליקציות (כמו HAL) לא יכולה להסתמך על זהות האפליקציה לצורך קבלת הרשאה. לכן, מטעמי בטיחות, ברירת המחדל ההנחה היא שכל שירות HwBinder מתייחס לכל הלקוחות שלו באופן שווה מורשה לבצע פעולות שהשירות מציע.
  2. שרתי HAL (קבוצת משנה של שירותי HwBinder) מכילים קוד עם שיעור המקרים של בעיות אבטחה בהשוואה לרכיבי system/core גישה לשכבות התחתונות של המקבץ (עד לחומרה) הזדמנויות הולכות וגדלות של עקיפה של מודל האבטחה של Android.

שירותי כספות

שירותי הכספת כוללים:

  • same_process_hwservice השירותים האלה (מהגדרתם) פועלים ב- את התהליך של הלקוח, כך שתהיה להם גישה זהה לזו של דומיין הלקוח שהתהליך מריץ.
  • coredomain_hwservice השירותים האלה לא יוצרים סיכונים שמשויכת לסיבה מספר 2.
  • hal_configstore_ISurfaceFlingerConfigs השירות הזה תוכנן במיוחד לשימוש בכל דומיין.
  • hal_graphics_allocator_hwservice הפעולות האלה מוצע על ידי שירות Binder של surfaceflinger, אילו אפליקציות מותרות כדי לגשת אליה.
  • hal_omx_hwservice זוהי גרסת HwBinder של mediacodec שירות Binder, שאליו יש לאפליקציות גישה.
  • hal_codec2_hwservice זוהי גרסה חדשה יותר של hal_omx_hwservice.

מאפיינים שאפשר להשתמש בהם

לכל hwservices הלא נחשבים בטוחים יש את המאפיין untrusted_app_visible_hwservice. לשרתי HAL התואמים יש המאפיין untrusted_app_visible_halserver. המכשירים שמופעלים עם Android 9 אסור להשתמש באף אחת מהאפשרויות מאפיין untrusted.

המלצה:

  • אפליקציות לא מהימנות צריכות במקום זאת לדבר עם שירות מערכת שמדבר הספק HIDL HAL. לדוגמה, אפליקציות יכולות לדבר אל binderservicedomain ואז אל mediaserver (שהוא binderservicedomain) בתורו מדבר עם hal_graphics_allocator.

    או

  • אפליקציות שזקוקות לגישה ישירה ל-vendor HALs דומיין מדיניות סחף שהוגדר על ידי הספק.

בדיקות של מאפייני קובץ

ב-Android 9 יש בדיקות זמן יצירה שמבטיחות שכל הקבצים כוללים את המאפיינים המתאימים (כמו כל הקבצים sysfs כוללים את מאפיין החובה sysfs_type).

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

מדיניות הפלטפורמה-ציבורית היא הליבה של תאימות ל-Android 8.0 של הארכיטקטורה מבלי לשמור על האיחוד של כללי מדיניות הפלטפורמה בגרסאות v1 ו-v2. הספקים נחשפים לקבוצת משנה של מדיניות הפלטפורמה, שכולל סוגים, מאפיינים וכללים שאפשר להשתמש בהם לגבי הסוגים והמאפיינים האלה. שהופך לאחר מכן לחלק ממדיניות הספק (כלומר vendor_sepolicy.cil).

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

מיפוי לשרשראות של מאפיינים

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

שמירה על יעד כדי להסתיר פרטי גרסה מכותב המדיניות יוצרת באופן אוטומטי את המאפיינים בעלי הגרסאות ומקצה אותם הסוגים המתאימים. במקרה הנפוץ של סוגים סטטיים, קל מאוד לעשות את זה: type_foo ממופה לtype_foo_v1.

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

שדרוג גרסאות

כדי לפשט את הפשטות, פלטפורמת Android מפרסמת גרסת מדיניות כשגרסה חדשה הסתעפות השחרור נחתך. כפי שתואר קודם, מספר הגרסה כלול PLATFORM_SEPOLICY_VERSION והוא בפורמט MM.nn, כאשר MM תואם לערך ה-SDK ו-nn הוא ערך ערך פרטי שנשמר ב- /platform/system/sepolicy. למשך לדוגמה, 19.0 ב-Kitkat, 21.0 ב-Lollipop, 22.0 עבור Lollipop-MR1 23.0 עבור Marshmallow, 24.0 ל-Nougat, 25.0 ל-Nougat-MR1, 26.0 ל-Oreo, 27.0 ל-Oreo-MR1, וגם 28.0 ל-Android 9. ערכי עלייה הם לא תמיד מספרים שלמים. עבור לדוגמה, אם מעבר MR על גרסה מחייב שינוי לא תואם system/sepolicy/public אבל לא עומס ב-API, אז המדיניות הזו הגרסה יכולה להיות: vN.1. הגרסה שמופיעה בפיתוח ההסתעפות היא 10000.0 של מכשירים שאי אפשר להשתמש בהם במשלוח.

יכול להיות שהגרסה הישנה ביותר תצא משימוש ב-Android במהלך ההעברה. לקבלת קלט לגבי מתי להוציא משימוש גרסה, מערכת Android עשויה לאסוף את מספר המכשירים דרך הספק כללי מדיניות שמפעילים את גרסת Android הזו ועדיין מקבלים את הפלטפורמה הראשית אם המספר נמוך מסף מסוים, הגרסה הזו הוצא משימוש.

השפעה על הביצועים של מספר מאפיינים

כפי שמתואר ב-https://github.com/SELinuxProject/cil/issues/9, מספר גדול של מאפיינים שמוקצים לסוג מסוים מובילים לבעיות בביצועים אירוע של השמטת מטמון של מדיניות.

זיהינו שזו בעיה ב-Android, אז שינויים נוצרו ל-Android 8.0 כדי להסיר מאפיינים שנוספו למדיניות על ידי שלנו, וכן להסיר מאפיינים שאינם בשימוש. השינויים האלה נפתרו רגרסיות של הביצועים.

המדיניות הציבורית והציבורית של המוצר System_ext

החל מ-Android 11, מחיצות system_ext ומחיצות המוצרים מותרות לייצא את הסוגים הציבוריים הייעודיים שלהם למחיצת הספק. סימון לייק לפלטפורמה למדיניות הציבורית, הספק משתמש בסוגים ובכללים שמתורגמים באופן אוטומטי את המאפיינים של הגרסאות. למשל מtype אל type_N, כאשר N היא הגרסה של הפלטפורמה שעליה נבנית המחיצה של הספק.

כאשר מחיצות המוצרים ומחיצות ה-system_ext מבוססות על אותה גרסת הפלטפורמה N, מערכת ה-build יוצרת קובצי מיפוי בסיסיים כדי system_ext/etc/selinux/mapping/N.cil והקבוצה product/etc/selinux/mapping/N.cil, שכוללות זהות מיפויים מ-type ל-type_N. הספק יכול גישה אל type באמצעות מאפיין ניהול הגרסאות type_N.

אם רק מחיצות המוצרים ומחיצות המערכת יעודכנו, נניח N אל N+1 (או מאוחר יותר), בזמן הספק נשאר ב-N, הספק עלול לאבד את הגישה אל שונים של system_ext ומחיצות המוצרים. כדי למנוע שבירה, system_ext ומחיצות מוצרים צריכים לספק קובצי מיפוי מבטון במאפייני type_N. כל שותף אחראי לתחזוקה של קובצי המיפוי, אם הם מתכננים לתמוך ספק של N עם N+1 (ואילך) system_ext ומחיצות מוצרים.

לשם כך, אנחנו מצפים מהשותפים:

  1. העתקת קובצי מיפוי הבסיס שנוצרו מ-N system_ext ומחיצות מוצרים לעץ המקור שלו.
  2. משנים את קובצי המיפוי לפי הצורך.
  3. להתקין את ממפים קבצים אל N+1 (או גרסה מאוחרת יותר) system_ext וגם מחיצות מוצרים.

לדוגמה, נניח שלמערכת N system_ext יש מזהה ציבורי אחד סוג בשם foo_type. ואז system_ext/etc/selinux/mapping/N.cil במחיצת system_ext של N תיראה כך:

(typeattributeset foo_type_N (foo_type))
(expandtypeattribute foo_type_N true)
(typeattribute foo_type_N)

אם מוסיפים את bar_type אל N+1 system_ext, וגם אם צריך למפות את bar_type ל-foo_type עבור ספק של N, אפשר לעדכן את N.cil דרך

(typeattributeset foo_type_N (foo_type))

עד

(typeattributeset foo_type_N (foo_type bar_type))

ואז מותקנת במחיצה של N+1 system_ext. ספק של N יכול להמשיך לגשת אל N+1 foo_type ו-bar_type של system_ext.

הוספת תוויות להקשרים של SELinux

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

ההקשרים של הקבצים

ב-Android 8.0 בוצעו השינויים הבאים ב-file_contexts:

  • כדי למנוע תקורת הידור נוספת במכשיר במהלך ההפעלה, file_contexts יפסיקו להופיע בפורמט הבינארי. במקום זאת, הם קובץ טקסט קריא של ביטויים רגולריים, כמו {property, service}_contexts (כפי שהיו לפני גרסה 7.0).
  • הקבצים מסוג file_contexts מחולקים בין שני קבצים:
    • plat_file_contexts
      • בפלטפורמת Android file_context שאין לה תוויות ספציפיות למכשיר, למעט הוספת תוויות לחלקים של מחיצה /vendor שצריך לתייג במדויק כדי לוודא שקובצי המדיניות פועלים בצורה תקינה.
      • חייב להימצא במחיצה של system בכתובת /system/etc/selinux/plat_file_contexts במכשיר ו ייטענו על ידי init בהתחלה, יחד עם הספק file_context.
    • vendor_file_contexts
      • file_context ספציפי למכשיר, שפותח על ידי שילוב האפליקציה file_contexts נמצאה בספריות שאליהן הפנו BOARD_SEPOLICY_DIRS במכשיר Boardconfig.mk קבצים.
      • חייבת להיות מותקנת ב- /vendor/etc/selinux/vendor_file_contexts אינץ' המחיצה vendor תיטען על ידי init בשעה ההתחלה ופלטפורמת file_context.

ההקשרים של הנכס

ב-Android 8.0, ה-property_contexts מחולק בין שני קבצים:

  • plat_property_contexts
    • בפלטפורמת Android property_context שאין לה תוויות ספציפיות למכשיר.
    • חייב להימצא במחיצה של system בכתובת /system/etc/selinux/plat_property_contexts והמכשיר ייטען עד init בהתחלה, יחד עם הספק property_contexts
  • vendor_property_contexts
    • property_context ספציפי למכשיר, שפותח על ידי שילוב האפליקציה property_contexts נמצאה בספריות שאליהן הפנו BOARD_SEPOLICY_DIRS במכשיר Boardconfig.mk קבצים.
    • חייב להימצא במחיצה של vendor בכתובת /vendor/etc/selinux/vendor_property_contexts ולהיות נטען על ידי init בהתחלה יחד עם הפלטפורמה property_context

ההקשרים של השירות

ב-Android 8.0, הservice_contexts מחולק בין קבצים:

  • plat_service_contexts
    • service_context ספציפי לפלטפורמת Android עבור servicemanager. בservice_context אין תוויות ספציפיות למכשיר.
    • חייב להימצא במחיצה של system בכתובת /system/etc/selinux/plat_service_contexts וייטען על ידי servicemanager בהתחלה יחד עם הספק service_contexts
  • vendor_service_contexts
    • service_context ספציפי למכשיר, שפותח על ידי שילוב האפליקציה service_contexts נמצאה בספריות שאליהן הפנו BOARD_SEPOLICY_DIRS במכשיר Boardconfig.mk קבצים.
    • חייב להימצא במחיצה של vendor בכתובת /vendor/etc/selinux/vendor_service_contexts והמכשיר ייטען עד servicemanager בהתחלה, וגם הפלטפורמה service_contexts
    • המערכת של servicemanager מחפשת את הקובץ הזה בזמן ההפעלה, אבל למכשיר TREBLE שתואם באופן מלא, vendor_service_contexts חייב להיות לא קיים. הסיבה לכך היא כל האינטראקציות בין vendor לבין system תהליכים חייבים לעבור hwservicemanager מתוך hwbinder.
  • plat_hwservice_contexts
    • פלטפורמת Android hwservice_context עבור התווית hwservicemanager שלא מכילה תוויות ספציפיות למכשיר.
    • חייב להימצא במחיצה של system בכתובת /system/etc/selinux/plat_hwservice_contexts וייטען על ידי hwservicemanager בהתחלה עם vendor_hwservice_contexts
  • vendor_hwservice_contexts
    • hwservice_context ספציפי למכשיר, שפותח על ידי שילוב האפליקציה hwservice_contexts נמצאה בספריות שאליהן הפנו BOARD_SEPOLICY_DIRS במכשיר Boardconfig.mk קבצים.
    • חייב להימצא במחיצה של vendor בכתובת /vendor/etc/selinux/vendor_hwservice_contexts ולהיות נטען על ידי hwservicemanager בהתחלה יחד עם plat_service_contexts
  • vndservice_contexts
    • service_context ספציפי למכשיר עבור vndservicemanager פותח על ידי שילוב נמצא vndservice_contexts בספריות שאליהן הפנו BOARD_SEPOLICY_DIRS במכשיר Boardconfig.mk
    • הקובץ חייב להימצא במחיצה vendor ב- /vendor/etc/selinux/vndservice_contexts וייטען על ידי vndservicemanager בהתחלה.

הקשרים ימיים

ב-Android 8.0, ה-seapp_contexts מחולק בין שני קבצים:

  • plat_seapp_contexts
    • בפלטפורמת Android seapp_context ללא סוג ספציפי של מכשיר שינויים.
    • חייב להימצא במחיצה של system בכתובת /system/etc/selinux/plat_seapp_contexts.
  • vendor_seapp_contexts
    • תוסף ספציפי למכשיר לפלטפורמה seapp_context שנוצר על ידי שילוב של seapp_contexts שנמצא בספריות מצביעים על ידי BOARD_SEPOLICY_DIRS Boardconfig.mk קבצים.
    • חייב להימצא במחיצה של vendor בכתובת /vendor/etc/selinux/vendor_seapp_contexts.

הרשאות MAC

ב-Android 8.0, ה-mac_permissions.xml מחולק בין שני קבצים:

  • פלטפורמה mac_permissions.xml
    • בפלטפורמת Android mac_permissions.xml שאין לה ספציפיים למכשיר.
    • חייב להימצא במחיצה של system בכתובת /system/etc/selinux/.
  • לא פלטפורמה mac_permissions.xml
    • תוסף לפלטפורמה ספציפי למכשיר mac_permissions.xml נוצרו מ- נמצא mac_permissions.xml בספריות שאליהן מפנות BOARD_SEPOLICY_DIRS של המכשיר קובצי Boardconfig.mk.
    • חייב להימצא במחיצה של vendor בכתובת /vendor/etc/selinux/.