בדף הזה מתוארות בעיות חשובות ותיקוני באגים שזוהו ב-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 מוגדר להפעיל תגובה לשגיאת ליבה קריטית כשהיא מזהה בעיה, כדי להגן על תקינות הליבה. עם זאת, השבתנו את ההתנהגות הזו מ-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
וחשיפה פוטנציאלית של מנהלי התקנים פגומים.
- סיכום: