הגדרת SELinux היא default-deny, כלומר כל גישה שיש לה hook בקרנל חייבת להיות מורשית במפורש על ידי המדיניות. כלומר, קובץ מדיניות מורכב מכמות גדולה של מידע לגבי כללים, סוגים, כיתות, הרשאות ועוד. המסמך הזה לא כולל הסבר מלא על SELinux, אבל חשוב להבין איך לכתוב כללי מדיניות כשמגדירים מכשירי Android חדשים. יש כבר הרבה מידע על SELinux. במסמכי התמיכה מפורטים משאבים מומלצים.
קובצי מפתח
כדי להפעיל את SELinux, צריך לשלב את הליבה העדכנית של Android ואז לשלב את הקבצים שנמצאים בספרייה system/sepolicy. כשמבצעים קומפילציה, הקבצים האלה כוללים את מדיניות האבטחה של ליבת SELinux ומכסים את מערכת ההפעלה Android במעלה הזרם.
באופן כללי, לא מומלץ לשנות את קובצי system/sepolicy
ישירות. במקום זאת, מוסיפים או עורכים קובצי מדיניות ספציפיים למכשיר בספרייה /device/manufacturer/device-name/sepolicy
. ב-Android 8.0 ואילך, השינויים שאתם מבצעים בקבצים האלה אמורים להשפיע רק על המדיניות בספריית הספקים. לפרטים נוספים על ההפרדה של מדיניות האבטחה הציבורית ב-Android 8.0 ואילך, אפשר לעיין במאמר התאמה אישית של מדיניות האבטחה ב-Android 8.0 ואילך. לא משנה איזו גרסת Android מותקנת, עדיין צריך לשנות את הקבצים האלה:
קבצים של מדיניות
קבצים שמסתיימים ב-*.te
הם קובצי מקור של מדיניות SELinux, שמוגדרים בהם דומיינים והתוויות שלהם. יכול להיות שתצטרכו ליצור קובצי מדיניות חדשים ב-
/device/manufacturer/device-name/sepolicy
,
אבל כדאי לנסות לעדכן קבצים קיימים איפה שאפשר.
קובצי הקשר
בקובצי ההקשר מציינים את התוויות של האובייקטים.
-
file_contexts
מקצה תוויות לקבצים ומשמש רכיבים שונים במרחב המשתמש. כשיוצרים מדיניות חדשה, צריך ליצור או לעדכן את הקובץ הזה כדי להקצות תוויות חדשות לקבצים. כדי להחילfile_contexts
חדש, צריך לבנות מחדש את קובץ האימג' של מערכת הקבצים או להריץ את הפקודהrestorecon
בקובץ כדי לשנות את התווית שלו. במהלך שדרוגים, שינויים ב-file_contexts
מוחלים אוטומטית על מחיצות המערכת ונתוני המשתמש כחלק מהשדרוג. אפשר גם להחיל שינויים באופן אוטומטי בשדרוג למחיצות אחרות על ידי הוספת קריאותrestorecon_recursive
לקובץ init.boardrc אחרי שהמחיצה מותקנת לקריאה ולכתיבה. -
genfs_contexts
מקצה תוויות למערכות קבצים, כמוproc
אוvfat
שלא תומכות במאפיינים מורחבים. ההגדרה הזו נטענת כחלק ממדיניות הליבה, אבל יכול להיות שהשינויים לא ייכנסו לתוקף עבור צמתי inode בליבה, ולכן צריך להפעיל מחדש את המחשב או לבטל את הטעינה של מערכת הקבצים ואז לטעון אותה מחדש כדי שהשינוי יחול באופן מלא. אפשר גם להקצות תוויות ספציפיות למתקנים ספציפיים, למשלvfat
באמצעות האפשרותcontext=mount
. -
property_contexts
מקצה תוויות למאפייני מערכת של Android כדי לקבוע אילו תהליכים יכולים להגדיר אותם. ההגדרה הזו נקראת על ידי התהליךinit
במהלך ההפעלה. -
service_contexts
מקצה תוויות לשירותי Android binder כדי לקבוע אילו תהליכים יכולים להוסיף (לרשום) ולמצוא (לחפש) הפניה ל-binder של השירות. ההגדרה הזו נקראת על ידי התהליךservicemanager
במהלך ההפעלה. -
seapp_contexts
מקצה תוויות לתהליכים של אפליקציות ולספריות של/data/data
. ההגדרה הזו נקראת על ידי התהליךzygote
בכל הפעלה של האפליקציה ועל ידיinstalld
במהלך ההפעלה. -
mac_permissions.xml
מקצה תגseinfo
לאפליקציות על סמך החתימה שלהן, ואופציונלית על סמך שם החבילה שלהן. אחר כך אפשר להשתמש בתגseinfo
כמפתח בקובץseapp_contexts
כדי להקצות תווית ספציפית לכל האפליקציות עם התגseinfo
הזה. ההגדרה הזו נקראת על ידיsystem_server
במהלך ההפעלה. -
keystore2_key_contexts
מקצה תוויות למרחבי שמות ב-Keystore 2. הדמוןkeystore2
אוכף את מרחבי השמות האלה. Keystore תמיד סיפק מרחבי שמות שמבוססים על UID/AID. בנוסף, Keystore 2 אוכף מרחבי שמות שמוגדרים ב-sepolicy. כאן אפשר למצוא תיאור מפורט של הפורמט והמוסכמות של הקובץ הזה.
קובץ ה-makefile BoardConfig.mk
אחרי עריכה או הוספה של קובצי מדיניות והקשר, מעדכנים את קובץ ה-makefile /device/manufacturer/device-name/BoardConfig.mk
כדי להפנות לספריית המשנה sepolicy
ולכל קובץ מדיניות חדש.
מידע נוסף על המשתנים BOARD_SEPOLICY
זמין בקובץ
system/sepolicy/README
.
BOARD_SEPOLICY_DIRS += \ <root>/device/manufacturer/device-name/sepolicy BOARD_SEPOLICY_UNION += \ genfs_contexts \ file_contexts \ sepolicy.te
אחרי הבנייה מחדש, SELinux מופעל במכשיר. עכשיו אפשר להתאים אישית את מדיניות SELinux כדי להוסיף תוספות למערכת ההפעלה Android, כמו שמתואר בקטע התאמה אישית, או לאמת את ההגדרה הקיימת כמו שמתואר בקטע אימות.
אחרי שקבצי המדיניות החדשים והעדכונים של BoardConfig.mk מוכנים, הגדרות המדיניות החדשות נבנות באופן אוטומטי בקובץ המדיניות הסופי של ליבת המערכת. מידע נוסף על בניית sepolicy במכשיר זמין במאמר Building sepolicy.
הטמעה
כדי להתחיל להשתמש ב-SELinux:
- מפעילים את SELinux בקרנל:
CONFIG_SECURITY_SELINUX=y
- משנים את הפרמטר kernel_cmdline או bootconfig כך ש:
אוBOARD_KERNEL_CMDLINE := androidboot.selinux=permissive
הפעולה הזו מיועדת רק לפיתוח הראשוני של מדיניות למכשיר. אחרי שיוצרים מדיניות ראשונית של bootstrap, מסירים את הפרמטר הזה כדי שהמכשיר יאכוף אותה או כדי שהמכשיר ייכשל בבדיקת CTS.BOARD_BOOTCONFIG := androidboot.selinux=permissive
- מפעילים את המערכת במצב הרשאה ורואים אילו דחיות מתרחשות במהלך ההפעלה:
ב-Ubuntu 14.04 ואילך: ב-Ubuntu 12.04:adb shell su -c dmesg | grep denied | audit2allow -p out/target/product/BOARD/root/sepolicy
adb pull /sys/fs/selinux/policy adb logcat -b all | audit2allow -p policy
- בודקים את הפלט כדי לראות אם יש אזהרות שדומות לטקסט
init: Warning! Service name needs a SELinux domain defined; please fix!
למידע על הוראות וכלים, אפשר לעיין בקטע אימות. - זיהוי מכשירים וקבצים חדשים אחרים שצריך לתייג.
- אפשר להשתמש בתוויות קיימות או ליצור תוויות חדשות לאובייקטים. כדאי לעיין בקבצים
*_contexts
כדי לראות איך הדברים סומנו בעבר, ולהשתמש בידע על המשמעויות של התוויות כדי להקצות תווית חדשה. מומלץ להשתמש בתווית קיימת שמתאימה למדיניות, אבל לפעמים צריך ליצור תוויות חדשות וכללים לגישה לתוויות האלה. מוסיפים את התוויות לקובצי ההקשר המתאימים. - מזהים דומיינים או תהליכים שצריכים להיות להם דומייני אבטחה משלהם.
סביר להניח שתצטרכו לכתוב מדיניות חדשה לגמרי לכל אחד מהם. לכל השירותים שנוצרו מ-
init
, למשל, צריך להיות מזהה משלהם. הפקודות הבאות עוזרות לגלות אילו שירותים עדיין פועלים (אבל צריך להשתמש בהן לכל השירותים):
adb shell su -c ps -Z | grep init
adb shell su -c dmesg | grep 'avc: '
- בודקים את
init.device.rc
כדי לזהות דומיינים שלא מוגדר להם סוג. כדאי לתת להם דומיין מוקדם בתהליך הפיתוח כדי להימנע מהוספת כללים ל-init
או מבלבול בין הגישות שלinit
לבין הגישות שמוגדרות במדיניות שלהם. - מגדירים את
BOARD_CONFIG.mk
לשימוש במשתניBOARD_SEPOLICY_*
. לפרטים על ההגדרה, אפשר לעיין בקובץ ה-README ב-system/sepolicy
. - בודקים את הקובץ init.device.rc ואת הקובץ fstab.device ומוודאים שכל שימוש ב-
mount
תואם למערכת קבצים עם תווית מתאימה, או שצוינה אפשרותcontext= mount
. - בודקים כל דחייה ויוצרים מדיניות SELinux כדי לטפל בכל אחת מהן בצורה נכונה. אפשר לעיין בדוגמאות שבקטע התאמה אישית.
מומלץ להתחיל עם המדיניות ב-AOSP ואז להשתמש בה כבסיס להתאמות אישיות משלכם. מידע נוסף על אסטרטגיית מדיניות ופירוט של חלק מהשלבים האלה זמין במאמר כתיבת מדיניות SELinux.
תרחישים לדוגמה
ריכזנו כאן דוגמאות ספציפיות לניצול לרעה שכדאי לקחת בחשבון כשיוצרים תוכנה ומדיניות SELinux שקשורה אליה:
קישורים סמליים: קישורים סמליים מופיעים כקבצים, ולכן הם נקראים לעיתים קרובות כקבצים, מה שעלול להוביל לניצול לרעה. לדוגמה, רכיבים מסוימים עם הרשאות מיוחדות, כמו init
, משנים את ההרשאות של קבצים מסוימים, לפעמים להרשאות פתוחות מדי.
לאחר מכן, התוקפים עשויים להחליף את הקבצים האלה בקישורים סימבוליים לקוד שהם שולטים בו, מה שמאפשר לתוקף לדרוס קבצים שרירותיים. אבל אם אתם יודעים שהאפליקציה שלכם אף פעם לא עוברת דרך קישור סמלי, אתם יכולים למנוע ממנה לעשות זאת באמצעות SELinux.
קובצי מערכת: כדאי לשקול את הסוג של קובצי המערכת שצריכים להיות שונים רק על ידי שרת המערכת. עם זאת, מאחר שהאפליקציות netd
, init
ו-vold
פועלות כ-root, הן יכולות לגשת לקבצי המערכת האלה. לכן, אם האבטחה של netd
תיפרץ, יכול להיות שהקבצים האלה ייפגעו וגם שרת המערכת עצמו.
באמצעות SELinux, אפשר לזהות את הקבצים האלה כקבצי נתונים של שרת המערכת.
לכן, הדומיין היחיד שיש לו הרשאת קריאה/כתיבה אליהם הוא שרת המערכת.
גם אם netd
ייפרץ, הוא לא יוכל להחליף דומיינים לדומיין של שרת המערכת ולגשת לקובצי המערכת האלה, למרות שהוא פועל כ-root.
נתוני אפליקציה: דוגמה נוספת היא סוג הפונקציות שחייבות לפעול כ-root אבל לא אמורות לקבל גישה לנתוני האפליקציה. התכונה הזו שימושית מאוד כי אפשר להגדיר טענות מגוונות, למשל שאסור לדומיינים מסוימים שלא קשורים לנתוני האפליקציה לגשת לאינטרנט.
setattr: בפקודות כמו chmod
ו-chown
, אפשר לזהות את קבוצת הקבצים שבה הדומיין המשויך יכול לבצע setattr
. יכול להיות שכל דבר אחר לא יורשה בשינויים האלה, גם אם הוא מבוצע על ידי משתמש עם הרשאות root. לכן, יכול להיות שאפליקציה תפעיל את chmod
ו-chown
מול התוויות app_data_files
, אבל לא מול shell_data_files
או system_data_files
.