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