כתיבת מדיניות SELinux

פרויקט הקוד הפתוח של Android (AOSP) מספק מדיניות בסיס יציבה עבור אפליקציות ושירותים שנפוצים בכל מכשירי Android. שותפים ב-AOSP משפרים את המדיניות הזו באופן קבוע. צפויה מדיניות הליבה כדי להוות כ-90-95% מהמדיניות הסופית לגבי מכשירים עם התאמות אישיות שמהוות את 5-10 האחוזים הנותרים. במאמר הזה נתמקד את ההתאמות האישיות שספציפיות למכשיר, איך לכתוב מדיניות ספציפית למכשיר, חלק מהמלכודות שכדאי להימנע מהן בדרך.

איסוף נתונים במכשיר

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

הפעלה במצב מתירני

כשמכשיר נמצא ב- במצב מתירני, הדחיות נרשמות ביומן, אבל הן לא נאכפות. מצב מתירנות חשוב לשני סיבות:

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

הדרך הפשוטה ביותר להעביר מכשיר למצב מתירני היא להשתמש פקודת ליבה (kernel) . את יכולה להוסיף את הקובץ הזה לקובץ BoardConfig.mk של המכשיר: platform/device/<vendor>/<target>/BoardConfig.mk. אחרי שמשנים את שורת הפקודה, מבצעים את הפקודה make clean ואז make bootimage, ופלאש את תמונת האתחול החדשה.

לאחר מכן, מאשרים את המצב הפחות מורשה באמצעות:

adb shell getenforce

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

אכיפה מוקדמת

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

הסרה או מחיקה של מדיניות קיימת

יש כמה סיבות טובות ליצירת מדיניות ספציפית למכשיר: במכשיר חדש, כולל:

טיפול בבעיות שקשורות לשירותי הליבה

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

avc: denied { open } for pid=1003 comm=”mediaserver” path="/dev/kgsl-3d0”
dev="tmpfs" scontext=u:r:mediaserver:s0 tcontext=u:object_r:device:s0
tclass=chr_file permissive=1
avc: denied { read write } for pid=1003 name="kgsl-3d0" dev="tmpfs"
scontext=u:r:mediaserver:s0
tcontext=u:object_r:device:s0 tclass=chr_file permissive=1

נטופל במלואו על ידי הוספת תווית נכונה ל-/dev/kgsl-3d0. לחשבון בדוגמה הזו, tcontext הוא device. הדבר מייצג הקשר ברירת מחדל שבו כל מה ב-/dev מקבל " "device", אלא אם מוקצית תווית ספציפית יותר. רק מקבלים את הפלט audit2allow כאן התוצאה תהיה כלל שגוי או מתירני מדי.

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

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

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

הוספת תווית לשירותים ולכתובת חדשים דחיות

שירותים התחלתיים נדרשים לפעול בדומיינים SELinux משלהם. בדוגמה הבאה, השירות 'foo' החדש בדומיין SELinux שלו מעניק לו הרשאות.

השירות הושק קובץ init.device.rc בתור:

service foo /system/bin/foo
    class core
  1. יצירת דומיין חדש בשם foo

    יצירת הקובץ device/manufacturer/device-name/sepolicy/foo.te עם התוכן הבא:

    # foo service
    type foo, domain;
    type foo_exec, exec_type, file_type;
    
    init_daemon_domain(foo)
    

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

  2. התווית: /system/bin/foo

    הוספת הטקסט הבא אל device/manufacturer/device-name/sepolicy/file_contexts:

    /system/bin/foo   u:object_r:foo_exec:s0
    

    הדבר מוודא שקובץ ההפעלה מסומן כראוי כדי ש-SELinux יריץ את בדומיין הנכון.

  3. ליצור תמונות אתחול ומערכת הפעלה (Flash) ולהריץ אותן.
  4. מצמצמים את כללי SELinux לדומיין.

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

חזרה למצב אכיפה

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

טעויות נפוצות

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

שימוש יתר בשלילה

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

allow { domain -untrusted_app } scary_debug_device:chr_file rw_file_perms

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

הכלל פגום בכמה דרכים. ההחרגה של untrusted_app קשה לעקוף את הבעיה, מכיוון שכל האפליקציות עשויות להריץ שירותים isolated_app דומיין. באופן דומה, אם דומיינים חדשים של אפליקציות צד שלישי יתווספו ל-AOSP, תהיה להם גם גישה אל scary_debug_device. הכלל מתירני מדי. רוב הדומיינים לא יפיקו תועלת גישה לכלי הזה לניפוי באגים. היה צריך לכתוב את הכלל כדי לאפשר רק הדומיינים שדורשים גישה.

תכונות לניפוי באגים בסביבת הייצור

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

החלופה הפשוטה ביותר היא להתיר את תכונת ניפוי הבאגים רק כש-SELinux מושבת בגרסאות build של eng/userdebug, כמו adb root ו- adb shell setenforce 0.

חלופה בטוחה נוספת היא לתחום הרשאות לניפוי באגים הצהרה userdebug_or_eng.

קיצוץ של גודל המדיניות

אפיון כללי מדיניות של SEAndroid בטבע מתארת מגמה מדאיגה בהתפתחות של ההתאמות האישיות של מדיניות המכשירים. מדיניות ספציפית למכשיר צריכה להוות 5-10% מהמדיניות הכוללת שפועלת על מכשיר. התאמות אישיות בטווח של 20%+ כמעט ודאי כוללות יותר דומיינים בעלי הרשאות ומדיניות ללא הרשאה.

מדיניות גדולה מדי:

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

בדוגמה הבאה מוצגים שני מכשירים שבהם מודל היא 50% ו-40% מהמדיניות בנושא מכשירים. שכתוב של המדיניות הניבה שיפורי אבטחה משמעותיים באופן משמעותי, ללא ירידה בפונקציונליות, שמוצגת בהמשך. (מכשירי AOSP של Shamu ו-Flounder כלולים לצורך השוואה.)

איור 1: השוואה בין גודל המדיניות הספציפית למכשיר לאחר בדיקת אבטחה.

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

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

מתן היכולת dac_override

הכחשה של dac_override פירושה שתהליך ההפרה מנסה לגשת לקובץ עם הרשאות שגויות של משתמש/קבוצה/עולם ב-Unix. הפתרון המתאים הוא כמעט אף פעם לא להעניק את ההרשאה dac_override. במקום זאת שינוי הרשאות ה-Unix בקובץ או בתהליך. מספר דומיינים כמו init, vold ו-installd באמת צריכים יכולת לשנות הרשאות של קובץ יוניקס כדי לגשת לקבצים של תהליכים אחרים. לבלוג של דן וולש כדי לקבל הסבר מעמיק יותר.