בדף הזה מתוארות בעיות חשובות ותיקוני באגים שזוהו ב-android-mainline
שעשויים להיות רלוונטיים לשותפים.
15 בנובמבר 2024
Clang עודכן לגרסה 19.0.1 עבור
android-mainline
ו-android16-6.12
- סיכום: בגרסה החדשה של Clang יש מנקה גבולות למערכים, שבו גודל המערך מאוחסן במשתנה נפרד שמקושר למערך באמצעות המאפיין
__counted_by
. התכונה הזו עלולה לגרום לתגובה לשגיאת ליבה קריטית אם גודל המערך לא מתעדכן כראוי. הודעת השגיאה נראית כך:
UBSAN: array-index-out-of-bounds in common/net/wireless/nl80211.c index 0 is out of range for type 'struct ieee80211_channel *[] __counted_by(n_channels)' (aka 'struct ieee80211_channel *[]')
פרטים: מנקה הגבולות חיוני להגנה על תקינות הליבה על ידי זיהוי גישה מחוץ לגבולות. בנוסף, כשהאפשרות
CONFIG_UBSAN_TRAP
מופעלת, מנקה הגבולות מפעיל חרדה בליבה (kernel panic) בכל גילוי.- הגרסה הקודמת של מנקה הגבולות בדקה רק מערכי גודל קבוע, ולא הצליחה לבדוק מערכי זיכרון שהוקצתה באופן דינמי. בגרסה החדשה נעשה שימוש במאפיין
__counted_by
כדי לקבוע את גבולות המערך בזמן הריצה ולזהות מקרים נוספים של גישה מחוץ לגבולות. עם זאת, במקרים מסוימים מתבצעת גישה למערך לפני שמוגדר משתנה הגודל, מה שמפעיל את מנקה הגבולות וגורם להתקפת חרדה (kernel panic) בליבה. כדי לפתור את הבעיה, צריך להגדיר את גודל המערך מיד אחרי הקצאת הזיכרון הבסיסי, כפי שמתואר ב-aosp/3343204.
- הגרסה הקודמת של מנקה הגבולות בדקה רק מערכי גודל קבוע, ולא הצליחה לבדוק מערכי זיכרון שהוקצתה באופן דינמי. בגרסה החדשה נעשה שימוש במאפיין
מידע על
CONFIG_UBSAN_SIGNED_WRAP
: הגרסה החדשה של Clang מבצעת סניטציה של זליגה (overflow) וחוסר (underflow) של מספרים שלמים חתימתים, למרות הדגל של המהדר-fwrapv
. הדגל-fwrapv
נועד להתייחס למספרים שלמים עם סימן כמספרים שלמים ללא סימן ב-two's complement עם התנהגות מוגדרת של זליגת נתונים.- ניטרול של זליגת נתונים ממערך שלמים בסימן בליבה של Linux יכול לעזור לזהות באגים, אבל יש מקרים שבהם זליגת הנתונים היא מכוונת, למשל ב-
atomic_long_t
. כתוצאה מכך,CONFIG_UBSAN_SIGNED_WRAP
הושבת כדי לאפשר ל-UBSAN לפעול רק ככלי לסינון גבולות.
- ניטרול של זליגת נתונים ממערך שלמים בסימן בליבה של Linux יכול לעזור לזהות באגים, אבל יש מקרים שבהם זליגת הנתונים היא מכוונת, למשל ב-
מידע על
CONFIG_UBSAN_TRAP
: UBSAN מוגדר להפעיל תגובה לשגיאת ליבה קריטית (kernel panic) כשהיא מזהה בעיה, כדי להגן על תקינות הליבה. עם זאת, השבתנו את ההתנהגות הזו מ-23 באוקטובר עד 12 בנובמבר. עשינו זאת כדי לבטל את החסימה של עדכון המהדר בזמן שפתרנו בעיות ידועות ב-__counted_by
.
- סיכום: בגרסה החדשה של Clang יש מנקה גבולות למערכים, שבו גודל המערך מאוחסן במשתנה נפרד שמקושר למערך באמצעות המאפיין
1 בנובמבר 2024
- השקה של Linux 6.12-rc4
- סיכום:
CONFIG_OF_DYNAMIC
עלול לגרום לנסיגה חמורה בנהגים פגומים. - הפרטים: במהלך המיזוג של Linux
6.12-rc1
ל-android-mainline
, שמנו לב לבעיות בחיבור של מנהלי התקנים מחוץ לעץ. השינוי שחשף את הבאגים בנהג זוהה כ-commit274aff8711b2 ("clk: Add KUnit tests for clks registered with struct clk_parent_data")
, והחזרנו אותו באופן זמני ב-aosp/3287735. השינוי מפעיל את הבחירה שלCONFIG_OF_OVERLAY
, שמפעילה את הבחירה שלCONFIG_OF_DYNAMIC
. כשמשתמשים ב-!OF_DYNAMIC
, ספירת ההפניות ב-of_node_get()
וב-of_node_put()
מושבתת למעשה, כי הן מיושמות כ-noops
. הפעלה מחדש שלOF_DYNAMIC
חושפת בעיות במנהלי התקנים שמטמיעים באופן שגוי את ספירת ההפניות שלstruct device_node
. כתוצאה מכך מתרחשות שגיאות מסוגים שונים, כמו פגיעה בזיכרון, שימוש לאחר שחרור (use-after-free) ודליפות זיכרון. - צריך לבדוק את כל השימושים בממשקי API שקשורים לניתוח OF. הרשימה הבאה היא חלקית, אבל היא כוללת מקרים שזיהינו:
- שימוש לאחר תקופת הניסיון בחינם (UAF):
- שימוש חוזר באותו ארגומנט
device_node
: הפונקציות האלה קוראות ל-of_node_put()
בצומת שצוין. יכול להיות שתצטרכו להוסיףof_node_get()
לפני הקריאה אליהן (לדוגמה, כשקוראים שוב ושוב עם אותו צומת כארגומנט):of_find_compatible_node()
of_find_node_by_name()
of_find_node_by_path()
of_find_node_by_type()
of_get_next_cpu_node()
of_get_next_parent()
of_get_next_child()
of_get_next_available_child()
of_get_next_reserved_child()
of_find_node_with_property()
of_find_matching_node_and_match()
- שימוש ב-
device_node
אחרי כל סוג של יציאה ממעגלים מסוימים:for_each_available_child_of_node_scoped()
for_each_available_child_of_node()
for_each_child_of_node_scoped()
for_each_child_of_node()
- שמירה על הפניות ישירות למאפייני
char *
מ-device_node
, לדוגמה, באמצעות:const char *foo = struct device_node::name
of_property_read_string()
of_property_read_string_array()
of_property_read_string_index()
of_get_property()
- שימוש חוזר באותו ארגומנט
- דליפות זיכרון:
- קבלת
device_node
ושיכחה לבטל את ההפניה (of_node_put()
). יש לפנות צמתים שמוחזרים מהם בשלב מסוים:of_find_compatible_node()
of_find_node_by_name()
of_find_node_by_path()
of_find_node_by_type()
of_find_node_by_phandle()
of_parse_phandle()
of_find_node_opts_by_path()
of_get_next_cpu_node()
of_get_compatible_child()
of_get_child_by_name()
of_get_parent()
of_get_next_parent()
of_get_next_child()
of_get_next_available_child()
of_get_next_reserved_child()
of_find_node_with_property()
of_find_matching_node_and_match()
- קבלת
- שמירת
device_node
מחזרה של לולאה. אם חוזרים או יוצאים מהקוד הבא, צריך לבטל את ההפניה הנותרת בשלב כלשהו:for_each_available_child_of_node()
for_each_child_of_node()
for_each_node_by_type()
for_each_compatible_node()
of_for_each_phandle()
- שימוש לאחר תקופת הניסיון בחינם (UAF):
- השינוי שצוין קודם שוחזר במהלך ההשקה של Linux
6.12-rc4
(ראו aosp/3315251), והוא מאפשר הפעלה מחדש שלCONFIG_OF_DYNAMIC
וחשיפה פוטנציאלית של מנהלי התקנים פגומים.
- סיכום: