ב-Android אנחנו ממליצים מאוד ליצרני ציוד מקורי לבדוק את ההטמעות של 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
), הוא מציין בערך מה התבצעו. במקרה הזה, משהו ניסה להתחבר ליציאת יצירת הזרם של Unix. - השדה
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
(הקשר מקור) מייצג את השחקן, במקרה הזה, הדימון (daemon) שלrmt_storage
. - Object – הערך
tcontext
(הקשר יעד) מייצג את האובייקט שעליו מתבצעת פעולה, במקרה הזה, kmem. - תוצאה – הרשומה
tclass
(target class) מציינת את סוג האובייקט שבו מבוצעת הפעולה, במקרה הזהchr_file
(character device).
העברת מקבצים של משתמשים וליבה (kernel)
במקרים מסוימים, המידע שביומן האירועים לא מספיק כדי לזהות את מקור הדחייה. לרוב כדאי לאסוף את שרשרת הקריאות, כולל הליבה ואזור המשתמש, כדי להבין טוב יותר למה הדחייה התרחשה.
לליבת Linux מהדורות האחרונות מוגדר נקודת מעקב בשם 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
. בגרסאות ליבה אחרות (kernel) אחרות, אפשר לבצע פקודות 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
כדי לבדוק את סטאק-טריי הנתון.
לדוגמה:
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.
מעבר למצב הרשאה רחבה
אפשר להשבית את אכיפת SELinux באמצעות adb בגרסאות build של userdebug או eng. לשם כך, קודם צריך להעביר את ADB ל-root על ידי הפעלת adb root
. לאחר מכן, כדי להשבית את האכיפה של SELinux, מריצים את הפקודה:
adb shell setenforce 0
או בשורת הפקודה בליבה (kernel) (במהלך ההפעלה המוקדמת של המכשיר):
androidboot.selinux=permissive
androidboot.selinux=enforcing
או באמצעות אתחול ב-Android 12:
androidboot.selinux=permissive
androidboot.selinux=enforcing
שימוש ב-audit2allow
הכלי audit2allow
מקבל דחיות dmesg
וממיר אותן להצהרות מדיניות תואמות של SELinux. לכן, הוא יכול להאיץ מאוד את הפיתוח של SELinux.
כדי להשתמש בו, מריצים את הפקודה:
adb pull /sys/fs/selinux/policy
adb 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
לכתוב זיכרון ליבה (kernel) - חור אבטחה נוצץ. לעיתים קרובות ההצהרות audit2allow
הן רק נקודת התחלה. אחרי שמשתמשים בהצהרות האלה, יכול להיות שתצטרכו לשנות את הדומיין המקור והתווית של היעד, וגם לשלב מאקרואים מתאימים כדי להגיע למדיניות טובה. לפעמים הדחייה שנבדקת לא אמורה להוביל לשינויים במדיניות בכלל, אלא צריך לשנות את האפליקציה שמפירה את המדיניות.