GKI 16-6.12 android-mainline errata

本頁將說明 android-mainline 中可能對合作夥伴造成重大影響的重要問題和錯誤修正內容。

2024 年 11 月 15 日

  • Clang 已更新至 android-mainlineandroid16-6.12 的 19.0.1 版本

    • 摘要:新版 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 後,邊界清理工具會針對任何發現觸發核心恐慌。

      • 先前版本的邊界消毒工具只會檢查固定大小的陣列,無法檢查動態配置的陣列。新版本會使用 __counted_by 屬性,在執行階段判斷陣列邊界,並偵測更多超出邊界存取的情況。不過,在某些情況下,陣列會在大小變數設定前存取,進而觸發邊界消毒程式,並導致核心恐慌。如要解決這個問題,請在分配底層記憶體後立即設定陣列大小,如 aosp/3343204 所示。
    • 關於 CONFIG_UBSAN_SIGNED_WRAP:新版 Clang 會清除帶符號整數溢位和不足,即使有 -fwrapv 編譯器標記也一樣。-fwrapv 標記旨在將帶符號整數視為帶有定義溢位行為的兩個互補無符號整數。

      • 雖然在 Linux 核心中清理帶正號整數溢位可協助找出錯誤,但有些情況下溢位是刻意為之,例如 atomic_long_t。因此,CONFIG_UBSAN_SIGNED_WRAP 已停用,讓 UBSAN 僅能做為邊界消毒工具。
    • 關於 CONFIG_UBSAN_TRAP:UBSAN 會在偵測到問題時觸發核心恐慌,以保護核心的完整性。不過,我們已從 10 月 23 日11 月 12 日停用這項行為。我們這麼做是為了在修正已知的 __counted_by 問題時,解除編譯器更新的封鎖。

2024 年 11 月 1 日

  • Linux 6.12-rc4 發布資訊
    • 摘要:CONFIG_OF_DYNAMIC 可能會導致有瑕疵的驅動程式嚴重回歸。
    • 詳細資料:在將 Linux 6.12-rc1 合併至 android-mainline 時,我們發現無法載入樹外驅動程式的問題。我們已將導致驅動程式錯誤的變更識別為 274aff8711b2 ("clk: Add KUnit tests for clks registered with struct clk_parent_data") 提交,並在 aosp/3287735 中暫時還原該變更。變更會選取 CONFIG_OF_OVERLAY,而 CONFIG_OF_OVERLAY 會選取 CONFIG_OF_DYNAMIC。在 !OF_DYNAMIC 中,of_node_get()of_node_put() 的參照計數功能會有效停用,因為它們是以 noops 實作。再次啟用 OF_DYNAMIC 會再次顯示驅動程式錯誤實作 struct device_node 參照計數的問題。這會導致各種錯誤,例如記憶體損毀、使用已釋放記憶體和記憶體流失。
    • 所有使用 OF 剖析相關 API 的情況都必須檢查。以下清單僅列出部分內容,但包含我們觀察到的案例:
      • 釋放後使用 (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()
        • device_node 保留指向 char * 屬性的直接指標,例如使用以下方式:
          • 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,並可能會公開有問題的驅動程式。