Android Live-LocK Daemon (llkd)

אנדרואיד 10 כולל את ה- Android Live-LocK Daemon ( llkd ), שנועד לתפוס ולהפחית מבוי סתום. רכיב llkd מספק מימוש עצמאי של ברירת מחדל, אך ניתן לחילופין לשלב את קוד llkd בשירות אחר, בין אם כחלק מהלולאה הראשית או כשרשור נפרד.

תרחישי זיהוי

ל- llkd יש שני תרחישי זיהוי: מצב D או Z מתמשך וחתימת מחסנית מתמשכת.

מצב D או Z מתמשך

אם שרשור נמצא במצב D (שינה בלתי ניתנת להפסקה) או Z (זומבי) ללא התקדמות קדימה למשך יותר מ- ro.llk.timeout_ms or ro.llk.[D|Z].timeout_ms , ה- llkd הורג את התהליך (או תהליך האב ). אם סריקה שלאחר מכן מראה שאותו תהליך ממשיך להתקיים, ה- llkd מאשר מצב של נעילה חיה ונכנס לפאניקה את הליבה באופן שמספק את דוח הבאגים המפורט ביותר עבור המצב.

ה- llkd כולל כלב שמירה עצמי שמזעיק אם llkd ננעל; watchdog כפול מהזמן הצפוי לזרום דרך ה-mainloop והדגימה היא כל ro.llk_sample_ms .

חתימת מחסנית מתמשכת

עבור מהדורות userdebug, ה- llkd יכול לזהות מנעולים חיים של ליבה באמצעות בדיקת חתימות מחסנית מתמשכת. אם לשרשור במצב כלשהו מלבד Z יש סמל ליבת ro.llk.stack מתמשך שמדווח על יותר מ- ro.llk.timeout_ms או ro.llk.stack.timeout_ms , ה- llkd יהרוג את התהליך (גם אם יש קדימה התקדמות תזמון). אם סריקה שלאחר מכן מראה שאותו תהליך ממשיך להתקיים, ה- llkd מאשר מצב של נעילה חיה ונכנס לפאניקה את הליבה באופן שמספק את דוח הבאגים המפורט ביותר עבור המצב.

בדיקת lldk נמשכת ברציפות כאשר מצב הנעילה החי קיים ומחפשת את המחרוזות המורכבות " symbol+0x" או " symbol.cfi+0x" בקובץ /proc/pid/stack ב-Linux. רשימת הסמלים נמצאת ב- ro.llk.stack ובברירת המחדל היא הרשימה המופרדת בפסיק של " cma_alloc,__get_user_pages,bit_wait_io,wait_on_page_bit_killable ".

סמלים צריכים להיות נדירים וקצרים מספיק כדי שבמערכת טיפוסית הפונקציה תראה רק פעם אחת במדגם במהלך תקופת הזמן הקצוב של ro.llk.stack.timeout_ms (דגימות מתרחשות בכל ro.llk.check_ms ). בגלל היעדר הגנת ABA, זו הדרך היחידה למנוע טריגר שווא. פונקציית הסמל חייבת להופיע מתחת לפונקציה הקוראת למנעול שיכול להתמודד. אם המנעול נמצא מתחת או בפונקציית הסמל, הסמל מופיע בכל התהליכים המושפעים, לא רק זה שגרם לנעילה.

כיסוי

יישום ברירת המחדל של llkd אינו מפקח על השרצים init , [kthreadd] או [kthreadd] . כדי שה- llkd יכסה את [kthreadd] -חוטים שהורדו:

  • אסור לנהגים להישאר במצב D מתמשך,

אוֹ

  • לנהגים חייבים להיות מנגנונים לשחזר את החוט אם הוא ייהרג חיצונית. לדוגמה, השתמש wait_event_interruptible() במקום wait_event() .

אם אחד מהתנאים לעיל מתקיים, ניתן להתאים את הרשימה השחורה llkd לכיסוי רכיבי ליבה. בדיקת סמל מחסנית כוללת רשימה שחורה נוספת של תהליך כדי למנוע הפרות של מדיניות בשירותים החוסמים פעולות ptrace .

נכסי אנדרואיד

ה- llkd מגיב למספר מאפייני אנדרואיד (המפורטים להלן).

  • מאפיינים בשם prop_ms הם באלפיות שניות.
  • מאפיינים המשתמשים במפריד פסיק (,) עבור רשימות משתמשים במפריד מוביל כדי לשמר את ערך ברירת המחדל, ולאחר מכן מוסיפים או מחסירים ערכים עם קידומות פלוס (+) ומינוס (-) אופציונליות, בהתאמה. עבור רשימות אלה, המחרוזת "false" היא שם נרדף לרשימה ריקה, וערכים ריקים או חסרים פונים לערך ברירת המחדל שצוין.

ro.config.low_ram

ההתקן מוגדר עם זיכרון מוגבל.

ro.debuggable

ההתקן מוגדר עבור userdebug או eng build.

ro.llk.sysrq_t

אם המאפיין הוא "eng", ברירת המחדל אינה ro.config.low_ram או ro.debuggable . אם נכון, זרוק את כל השרשורים ( sysrq t ).

ro.llk.enable

אפשר להפעיל את דמון הנעילה החיה. ברירת המחדל היא שקר.

llk.enable

הוערך עבור בניית eng. ברירת המחדל היא ro.llk.enable .

ro.khungtask.enable

אפשר להפעיל את הדמון [khungtask] . ברירת המחדל היא שקר.

khungtask.enable

הוערך עבור בניית eng. ברירת המחדל היא ro.khungtask.enable .

ro.llk.mlockall

אפשר קריאה ל- mlockall() . ברירת המחדל היא שקר.

ro.khungtask.timeout

[khungtask] מגבלת זמן מקסימלית. ברירת המחדל היא 12 דקות.

ro.llk.timeout_ms

מגבלת זמן מקסימלית D או Z. ברירת המחדל היא 10 דקות. הכפיל את הערך הזה כדי להגדיר את כלב השמירה של האזעקה עבור llkd .

ro.llk.D.timeout_ms

D מגבלת זמן מקסימלית. ברירת המחדל היא ro.llk.timeout_ms .

ro.llk.Z.timeout_ms

ז מגבלת זמן מקסימלית. ברירת המחדל היא ro.llk.timeout_ms .

ro.llk.stack.timeout_ms

בודק את מגבלת הזמן המקסימלית של סמלי מחסנית מתמשכים. ברירת המחדל היא ro.llk.timeout_ms . פעיל רק ב-userdebug או ב-eng builds .

ro.llk.check_ms

דוגמאות של שרשורים עבור D או Z. ברירת המחדל היא שתי דקות.

ro.llk.stack

בודק סמלי מחסנית ליבה שאם נוכחים באופן מתמשך יכולים להצביע על כך שתת-מערכת נעולה. ברירת המחדל היא cma_alloc,__get_user_pages,bit_wait_io,wait_on_page_bit_killable רשימה מופרדת בפסיקים של סמלי ליבה. הצ'ק אינו עושה ABA תזמון קדימה אלא על ידי סקר כל ro.llk_check_ms במהלך התקופה ro.llk.stack.timeout_ms , כך שסמלי מחסנית צריכים להיות נדירים וחולפים במיוחד (לא סביר מאוד שסמל יופיע באופן מתמשך בכלל דוגמאות של הערימה). בודק התאמה ל- " symbol+0x" או " symbol.cfi+0x" בהרחבת הערימה. זמין רק ב-userdebug או ב-eng builds ; חששות אבטחה בבניית משתמש גורמות להרשאות מוגבלות שמונעות בדיקה זו.

ro.llk.blacklist.process

ה- llkd אינו צופה בתהליכים שצוינו. ברירת המחדל היא 0,1,2 ( kernel , init ו- [kthreadd] ) בתוספת שמות תהליכים init,[kthreadd],[khungtaskd],lmkd,llkd,watchdogd, [watchdogd],[watchdogd/0],...,[watchdogd/get_nprocs-1] . תהליך יכול להיות הפניה comm , cmdline או pid . ברירת מחדל אוטומטית יכולה להיות גדולה מגודל הנכס המקסימלי הנוכחי של 92.

ro.llk.blacklist.הורה

ה- llkd אינו צופה בתהליכים שיש להם את ההורה/ים שצוינו. ברירת המחדל היא 0,2,adbd&[setsid] ( kernel , [kthreadd] ו- adbd רק עבור זומבי setsid ). מפריד אמפרסנד (&) מציין שהתעלמות מהאב רק בשילוב עם תהליך הילד היעד. Ampersand נבחר משום שהוא אף פעם לא חלק משם תהליך; עם זאת, setprop במעטפת מחייב את האמפרסנד להיות escaped או ציטוט, למרות שקובץ init rc שבו זה מצוין בדרך כלל אין בעיה זו. תהליך אב או יעד יכול להיות הפניה comm , cmdline או pid .

ro.llk.blacklist.uid

ה- llkd אינו צופה בתהליכים התואמים ל-uid/ים שצוינו. רשימה מופרדת בפסיקים של מספרי UID או שמות. ברירת המחדל היא ריקה או שקר.

ro.llk.blacklist.process.stack

ה- llkd אינו מפקח על תת-קבוצת התהליכים שצוינה עבור חתימות מחסנית נעילה חיה. ברירת המחדל היא שמות התהליך init,lmkd.llkd,llkd,keystore,ueventd,apexd,logd . מונע את הפרת ה-sepolicy הקשורה לתהליכים שחוסמים ptrace (כיוון שלא ניתן לבדוק אותם). פעיל רק ב-userdebug ו-eng builds . לפרטים על סוגי בנייה, עיין בבניית אנדרואיד .

דאגות אדריכליות

  • המאפיינים מוגבלים ל-92 תווים (עם זאת, מתעלמים מכך עבור ברירות מחדל המוגדרות בקובץ include/llkd.h במקורות).
  • הדמון המובנה [khungtask] הוא גנרי מדי ומופעל על קוד נהג שיושב במצב D יותר מדי. מעבר ל-S יהפוך את המשימות לניתנות להרוג (וניתנות להחיות על ידי מנהלי התקנים במידת הצורך).

ממשק הספרייה (אופציונלי)

ניתן לשלב את ה- llkd באופן אופציונלי בדמון מיוחס אחר באמצעות ממשק C הבא מהרכיב libllkd :

#include "llkd.h"
bool llkInit(const char* threadname) /* return true if enabled */
unsigned llkCheckMillseconds(void)   /* ms to sleep for next check */

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