מערכת Android ממליצה ליצרני ציוד מקורי (OEM) לבדוק את ההטמעות של SELinux באופן יסודי. יצרנים שמטמיעים את SELinux צריכים להחיל את המדיניות החדשה קודם על קבוצת מכשירי בדיקה.
אחרי שמחילים מדיניות חדשה, חשוב לוודא ש-SELinux פועל במצב הנכון במכשיר באמצעות הפקודה getenforce.
הפקודה הזו מדפיסה את המצב הגלובלי של SELinux: או Enforcing או Permissive. כדי לקבוע את מצב SELinux לכל דומיין, צריך לבדוק את הקבצים המתאימים או להריץ את הגרסה העדכנית של sepolicy-analyze עם הדגל המתאים (-p), שמופיע ב-
/platform/system/sepolicy/tools/.
קריאת נתוני הדחיות
בודקים אם יש שגיאות, שמנותבות כיומני אירועים אל dmesg
ואל logcat וניתן לראות אותן באופן מקומי במכשיר. יצרנים צריכים לבדוק את הפלט של SELinux בdmesg במכשירים האלה ולשפר את ההגדרות לפני הפרסום לציבור במצב מתירני, ובסופו של דבר לעבור למצב אכיפה. הודעות ביומן SELinux מכילות את avc: ולכן אפשר למצוא אותן בקלות באמצעות grep. אפשר לתעד את יומני הדחייה שמתעדכנים כל הזמן על ידי הפעלת הפקודה cat /proc/kmsg, או לתעד יומני דחייה מההפעלה הקודמת על ידי הפעלת הפקודה cat /sys/fs/pstore/console-ramoops.
הודעות השגיאה של SELinux מוגבלות בקצב שלהן אחרי השלמת האתחול, כדי למנוע הצפה של היומנים. כדי לוודא שאתם רואים את כל ההודעות הרלוונטיות, אתם יכולים להשבית את ההגדרה הזו על ידי הפעלת הפקודה adb shell auditctl -r 0.
בעזרת הפלט הזה, יצרנים יכולים לזהות בקלות מקרים שבהם משתמשי מערכת או רכיבים מפרים את מדיניות SELinux. יצרנים יכולים לתקן את התפקוד הלא תקין הזה באמצעות שינויים בתוכנה, במדיניות SELinux או בשניהם.
באופן ספציפי, הודעות היומן האלה מציינות אילו תהליכים ייכשלו במצב אכיפה ולמה. לדוגמה:
avc: denied { connectto } for pid=2671 comm="ping" path="/dev/socket/dnsproxyd"
scontext=u:r:shell:s0 tcontext=u:r:netd:s0 tclass=unix_stream_socket
כך מסבירים את הפלט:
- הסמל
{ connectto }שלמעלה מייצג את הפעולה שמתבצעת. יחד עםtclassבסוף (unix_stream_socket), אפשר להבין בערך מה נעשה ומה היה היעד של הפעולה. במקרה הזה, משהו ניסה להתחבר לשקע של זרם יוניקס. - הערך
scontext (u:r:shell:s0)מציין את ההקשר שבו הפעולה התחילה. במקרה הזה, מדובר במשהו שפועל כמעטפת. - השדה
tcontext (u:r:netd:s0)מציין את ההקשר של יעד הפעולה. במקרה הזה, זהו unix_stream_socket שבבעלותnetd. - הסמל
comm="ping"בחלק העליון מספק רמז נוסף לגבי מה שהופעל בזמן שנוצרה הדחייה. במקרה הזה, זו רמז די טוב.
דוגמה נוספת:
adb shell su root dmesg | grep 'avc: '
פלט:
<5> type=1400 audit: avc: denied { read write } for pid=177
comm="rmt_storage" name="mem" dev="tmpfs" ino=6004 scontext=u:r:rmt:s0
tcontext=u:object_r:kmem_device:s0 tclass=chr_file
אלה הרכיבים העיקריים מהדחייה הזו:
- פעולה – הפעולה שניסו לבצע מודגשת בסוגריים,
read writeאוsetenforce. - Actor – הרשומה
scontext(הקשר המקור) מייצגת את הגורם המבצע, ובמקרה הזה את דמוןrmt_storage. - Object – הרשומה
tcontext(הקשר של היעד) מייצגת את האובייקט שעליו מתבצעת הפעולה, במקרה הזה kmem. - תוצאה – הערך
tclass(target class) מציין את סוג האובייקט שעליו מתבצעת הפעולה, ובמקרה הזה מדובר ב-chr_file(character device).
העברה של מחסניות של משתמשים וליבות
במקרים מסוימים, המידע שכלול ביומן האירועים לא מספיק כדי לאתר את מקור הדחייה. לעתים קרובות כדאי לאסוף את שרשרת הקריאות, כולל מרחב ליבת המערכת ומרחב המשתמש, כדי להבין טוב יותר למה נדחתה הבקשה.
ליבות עדכניות מגדירות נקודת מעקב בשם avc:selinux_audited. משתמשים ב-Android
simpleperf כדי להפעיל את נקודת המעקב הזו ולתעד את שרשרת הקריאות.
הגדרה נתמכת
- יש תמיכה בליבת Linux מגרסה 5.10 ואילך, ובמיוחד בענפים של ליבת Android Common Kernel:
mainline
ו-
android12-5.10.
יש תמיכה גם בענף android12-5.4. אפשר להשתמש ב-
simpleperfכדי לבדוק אם נקודת המעקב מוגדרת במכשיר:adb root && adb shell simpleperf list | grep avc:selinux_audited. בגרסאות ליבה אחרות, אפשר לבחור קומיטים (commit) dd81662 ו-30969bc. - צריכה להיות אפשרות לשחזר את האירוע שמבצעים בו ניפוי באגים. אי אפשר לתמוך באירועים של זמן האתחול באמצעות simpleperf, אבל יכול להיות שעדיין תוכלו להפעיל מחדש את השירות כדי להפעיל את האירוע.
תיעוד שרשרת השיחות
השלב הראשון הוא לתעד את האירוע באמצעות simpleperf record:
adb shell -t "cd /data/local/tmp && su root simpleperf record -a -g -e avc:selinux_audited"
לאחר מכן, צריך להפעיל את האירוע שגרם לדחייה. אחרי כן, צריך להפסיק את ההקלטה. בדוגמה הזו, אם משתמשים ב-Ctrl-c, הדגימה אמורה להתרחש:
^Csimpleperf I cmd_record.cpp:751] Samples recorded: 1. Samples lost: 0.
לבסוף, אפשר להשתמש ב-simpleperf report כדי לבדוק את ה-stacktrace שנתפס.
לדוגמה:
adb shell -t "cd /data/local/tmp && su root simpleperf report -g --full-callgraph"
[...]
Children Self Command Pid Tid Shared Object Symbol
100.00% 0.00% dmesg 3318 3318 /apex/com.android.runtime/lib64/bionic/libc.so __libc_init
|
-- __libc_init
|
-- main
toybox_main
toy_exec_which
dmesg_main
klogctl
entry_SYSCALL_64_after_hwframe
do_syscall_64
__x64_sys_syslog
do_syslog
selinux_syslog
slow_avc_audit
common_lsm_audit
avc_audit_post_callback
avc_audit_post_callback
שרשרת הקריאות שלמעלה היא שרשרת קריאות מאוחדת של ליבת המערכת ומרחב המשתמש. הוא מספק תצוגה טובה יותר של זרימת הקוד, כי הוא מתחיל את המעקב ממרחב המשתמשים ועד לליבה שבה מתרחשת הדחייה. מידע נוסף על simpleperf זמין במאמר Simpleperf Executable commands reference
מעבר למצב הרשאה
אפשר להשבית את האכיפה של SELinux באמצעות adb בגרסאות userdebug או eng. כדי לעשות זאת, קודם צריך להעביר את ADB למצב root על ידי הפעלת adb root. לאחר מכן, כדי להשבית את האכיפה של SELinux, מריצים את הפקודה:
adb shell setenforce 0
או בשורת הפקודה של ליבת המערכת (במהלך הפעלה מוקדמת של המכשיר):
androidboot.selinux=permissiveandroidboot.selinux=enforcing
או דרך bootconfig ב-Android 12:
androidboot.selinux=permissiveandroidboot.selinux=enforcing
שימוש ב-audit2allow
הכלי audit2allow לוקח דחיות של dmesg וממיר אותן להצהרות מדיניות תואמות של SELinux. לכן, הוא יכול להאיץ מאוד את פיתוח SELinux.
כדי להשתמש בו, מריצים את הפקודה:
adb pull /sys/fs/selinux/policyadb logcat -b events -d | audit2allow -p policy
עם זאת, חשוב לבדוק כל תוסף פוטנציאלי כדי לוודא שהוא לא מבקש הרשאות רחבות מדי. לדוגמה, אם מזינים ל-audit2allow את הדחייה rmt_storage שמופיעה למעלה, מתקבלת הצעת ההצהרה הבאה של מדיניות SELinux:
#============= shell ==============
allow shell kernel:security setenforce;
#============= rmt ==============
allow rmt kmem_device:chr_file { read write };
כך ניתנת ל-rmt האפשרות לכתוב זיכרון ליבה, וזו פרצת אבטחה חמורה. לעתים קרובות, הצהרות audit2allow הן רק נקודת התחלה. אחרי שמשתמשים בהצהרות האלה, יכול להיות שיהיה צורך לשנות את דומיין המקור ואת התווית של היעד, וגם לשלב פקודות מאקרו מתאימות, כדי להגיע למדיניות טובה. לפעמים הדחייה שנבדקת לא צריכה להוביל לשינויים במדיניות, אלא לשינויים באפליקציה הבעייתית.