Android 10 כולל את הדימון (daemon) ל-Android Live-lock
(llkd
), שמטרתו לזהות ולצמצם מבוי סתום של ליבה (kernel). llkd
מספק הטמעה עצמאית שמוגדרת כברירת מחדל, אבל אפשר
או לשלב את הקוד של llkd
בשירות אחר,
את הלולאה הראשית או כשרשור נפרד.
תרחישי זיהוי
ב-llkd
יש שני תרחישי זיהוי: מצב D או Z קבוע, ומצב קבוע
חתימה בסטאק.
מצב D או Z קבוע
אם שרשור נמצא במצב D (שינה ללא הפרעות) או Z (זומבי) ללא העברה
התקדמות של יותר מ-ro.llk.timeout_ms or ro.llk.[D|Z].timeout_ms
,
הפקודה llkd
מסתיימת בתהליך (או בתהליך הורה). אם בסריקה לאחר מכן מופיע
אותו תהליך עדיין קיים, ה-llkd
מאשר תנאי של נעילה בזמן אמת
מבהיל את הליבה באופן שיספק את דוח איתור הבאגים המפורט ביותר
תנאי.
llkd
כולל טיימר מפקח (watchdog) ששולח התראות אם llkd
ננעל. הטיימר המפקח (watchdog) הוא
להכפיל את משך הזמן הצפוי לזרימה דרך הלולאה הראשית, וכל דגימה
ro.llk_sample_ms
.
חתימת מקבץ מתמיד
בגרסאות של ניפוי באגים למשתמשים, llkd
יכול לזהות נעילות חיים של ליבה (kernel) באמצעות שימוש קבוע
בדיקת חתימת סטאק. אם בשרשור בכל מצב חוץ מ-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
ב-AI.
נכסי Android
llkd
מגיב לכמה נכסי Android (מפורטים בהמשך).
- נכסים בשם
prop_ms
נמצאים באלפיות שנייה. - מאפיינים שבהם נעשה שימוש בפסיק (,) לרשימות, תו מפריד מוביל כדי
לשמור את ערך ברירת המחדל, ואז להוסיף או להחסיר רשומות עם סימן פלוס אופציונלי
תחיליות (+) ומינוס (-) בהתאמה. ברשימות האלה, המחרוזת
false
מקביל לרשימה ריקה, וערכים ריקים או חסרים מפנים את ערך ברירת המחדל שצוין.
ro.config.low_ram
המכשיר מוגדר עם זיכרון מוגבל.
Ro.debuggable
המכשיר מוגדר לניפוי באגים אצל משתמשים או ל-build מחדש.
ro.llk.sysrq_t
אם המאפיין הוא eng
, ברירת המחדל היא לא ro.config.low_ram
או ro.debuggable
.
אם הערך שלו הוא true
, ביטול כל השרשורים (sysrq t
).
ro.llk.enable
אישור להפעלת דימון (daemon) של נעילה בשידור חי. ברירת המחדל היא false
.
llk.enable
בוצעה הערכה לפיתוח גרסאות build לעידוד השימוש באפליקציה. ברירת המחדל היא ro.llk.enable
.
ro.kungtask.enable
אישור להפעלת הדימון (daemon) של [khungtask]
. ברירת המחדל היא false
.
kungtask.enable
בוצעה הערכה לפיתוח גרסאות build לעידוד השימוש באפליקציה. ברירת המחדל היא ro.khungtask.enable
.
ro.llk.mlockall
הפעלת השיחה אל mlockall()
. ברירת המחדל היא false
.
ro.khutask.timeout
מגבלת זמן של [khungtask]
לכל היותר. ברירת המחדל היא 12 דקות.
ro.llk.timeout_ms
מגבלת זמן מקסימלית D או Z. ברירת המחדל היא 10 דקות. צריך להכפיל את הערך הזה כדי להגדיר את
טיימר מפקח (watchdog) של llkd
.
ro.llk.D.timeout_ms
מגבלת זמן מקסימלית D. ברירת המחדל היא ro.llk.timeout_ms
.
ro.llk.Z.timeout_ms
מגבלת זמן מקסימלית של Z. ברירת המחדל היא ro.llk.timeout_ms
.
ro.llk.stack.timeout_ms
בדיקת מגבלת הזמן המקסימלית של סמלי ערימה קבועים. ברירת המחדל היא
ro.llk.timeout_ms
פעיל רק ב-userdebug או בגרסאות build של יצירת עניין.
ro.llk.check_ms
דגימות של שרשורים ל-D או Z. ברירת המחדל היא שתי דקות.
ro.llk.stack
חיפוש סמלים של סטאק ליבה (kernel), שאם הם קיימים באופן קבוע מציינים
מערכת המשנה נעולה. ברירת המחדל היא
cma_alloc,__get_user_pages,bit_wait_io,wait_on_page_bit_killable
רשימה של סמלי ליבה (kernel) שמופרדים בפסיקים. הבדיקה לא מאפשרת תזמון העברה
ABA, למעט באמצעות סקרים בכל ro.llk_check_ms
במהלך התקופה
ro.llk.stack.timeout_ms
, לכן סמלי מקבצים צריכים להיות נדירים
חולף (לא סביר שסמל יופיע באופן קבוע
דוגמאות של המקבץ). מחפש התאמה עבור symbol+0x
או
symbol.cfi+0x
בהרחבת מקבץ. זמין רק ב-userdebug או in-eng
builds; בעיות אבטחה בגרסאות build של משתמשים גורמות להרשאות מוגבלות
למנוע את הבדיקה הזו.
ro.llk.black.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.black.parent
llkd
לא עוקב אחרי תהליכים שיש להם את תבניות ההורה שצוינו. ברירת מחדל
היא 0,2,adbd&[setsid]
(kernel
, [kthreadd]
, ו-adbd
רק לזומבים
setsid
). מפריד אמפרסנד (&) מציין שהמערכת מתעלמת רק מההורה
בשילוב עם תהליך הצאצא של היעד. אמפרסנד נבחר מפני שהוא
הוא אף פעם לא חלק משם תהליך. אבל setprop
במעטפת דורש
כדי לסמן את האמפרסנד בתו בריחה (escape) או לצטט אותן, למרות שקובץ init rc
שבו
בדרך כלל, אין את הבעיה הזו. הורה או תהליך יעד יכולים להיות
הפניה אל comm
, cmdline
או pid
.
ro.llk.black.uid
הפונקציה llkd
לא עוקבת אחרי תהליכים שתואמים ל-UID שצוין.
רשימה של מספרים או שמות המופרדים באמצעות פסיקים. ברירת המחדל ריקה או false
.
ro.llk.black.process.stack
llkd
לא עוקב אחר קבוצת המשנה שצוינה של תהליכים לסטאק תוכנות נעילה בזמן אמת
חתימות. ברירת המחדל היא שמות התהליכים
init,lmkd.llkd,llkd,keystore,ueventd,apexd,logd
מניעת פריצה
הפרה המשויכת לתהליכים שחוסמים את ptrace
(כי הם לא יכולים להיות
מסומנת). פעיל רק ב-userdebug ובגרסאות build של מעורבות. פרטים על build
הסוגים, קראו את המאמר יצירת Android.
חששות בנוגע לארכיטקטורה
- המאפיינים מוגבלים ל-92 תווים (עם זאת, ברירת המחדל מתעלמת מהמאפיין הזה
שהוגדר בקובץ
include/llkd.h
במקורות). - הדימון המובנה של
[khungtask]
הוא כללי מדי והחיפוש שלו מתבצע באמצעות קוד הנהג נמצאת במצב D יותר מדי. המעבר ל-S יגרום לכך שהמשימות יימחקו (וניתן להחזיר אותם במקרה הצורך על ידי הנהגים).
ממשק הספרייה (אופציונלי)
אפשר לשלב את llkd
בדימון (daemon) אחר בעל הרשאות באמצעות
ממשק C הבא מהרכיב libllkd
:
#include "llkd.h"
bool llkInit(const char* threadname) /* return true if enabled */
unsigned llkCheckMillseconds(void) /* ms to sleep for next check */
אם מציינים שם שרשור, השרשור מתחיל באופן אוטומטי. אחרת, מבצע הקריאה החוזרת
חייב לקרוא לפונקציה llkCheckMilliseconds
בלולאה הראשית. הפונקציה מחזירה את הערך
פרק זמן לפני הקריאה הצפויה הבאה ל-handler הזה.