תיקון שגיאה של GKI 16-6.12 android-mainline

בדף הזה מתוארות בעיות חשובות ותיקוני באגים שזוהו ב-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 לפעול רק ככלי לסינון גבולות.
    • מידע על CONFIG_UBSAN_TRAP: UBSAN מוגדר להפעיל תגובה לשגיאת ליבה קריטית (kernel panic) כשהיא מזהה בעיה, כדי להגן על תקינות הליבה. עם זאת, השבתנו את ההתנהגות הזו מ-23 באוקטובר עד 12 בנובמבר. עשינו זאת כדי לבטל את החסימה של עדכון המהדר בזמן שפתרנו בעיות ידועות ב-__counted_by.

1 בנובמבר 2024

  • השקה של Linux 6.12-rc4
    • סיכום: CONFIG_OF_DYNAMIC עלול לגרום לנסיגה חמורה בנהגים פגומים.
    • הפרטים: במהלך המיזוג של Linux 6.12-rc1 ל-android-mainline, שמנו לב לבעיות בחיבור של מנהלי התקנים מחוץ לעץ. השינוי שחשף את הבאגים בנהג זוהה כ-commit 274aff8711b2 ("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()
    • השינוי שצוין קודם שוחזר במהלך ההשקה של Linux 6.12-rc4 (ראו aosp/3315251), והוא מאפשר הפעלה מחדש של CONFIG_OF_DYNAMIC וחשיפה פוטנציאלית של מנהלי התקנים פגומים.