GKI 16-6.12 android-mainline errata

Auf dieser Seite werden wichtige Probleme und Fehlerkorrekturen in android-mainline beschrieben, die für Partner von Bedeutung sein könnten.

15. November 2024

  • Clang wurde für android-mainline und android16-6.12 auf Version 19.0.1 aktualisiert

    • Zusammenfassung: Die neue Version von Clang führt einen Bounds-Sanitizer für Arrays ein, bei dem die Größe des Arrays in einer separaten Variablen gespeichert wird, die über das Attribut __counted_by mit dem Array verknüpft ist. Diese Funktion kann zu einer Kernel Panic führen, wenn die Arraygröße nicht richtig aktualisiert wird. Die Fehlermeldung sieht so aus:
    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 *[]')
    
    • Details: Der Bounds-Sanitizer ist unerlässlich, um die Integrität des Kernels zu schützen, indem er Zugriffe außerhalb des zulässigen Bereichs erkennt. Wenn CONFIG_UBSAN_TRAP aktiviert ist, löst der Bounds-Sanitizer bei jedem Fund eine Kernel-Panik aus.

      • In der vorherigen Version des Bounds Sanitizer wurden nur Arrays mit fester Größe geprüft. Dynamisch zugewiesene Arrays konnten nicht geprüft werden. In der neuen Version wird das Attribut __counted_by verwendet, um die Arraygrenzen zur Laufzeit zu ermitteln und mehr Fälle von Zugriffen außerhalb des zulässigen Bereichs zu erkennen. In einigen Fällen wird jedoch auf das Array zugegriffen, bevor die Größenvariable festgelegt wird. Dies löst den Bounds-Sanitizer aus und führt zu einem Kernel-Panic. Um dieses Problem zu beheben, legen Sie die Größe des Arrays unmittelbar nach der Zuweisung des zugrunde liegenden Speichers fest, wie in aosp/3343204 dargestellt.
    • Zu CONFIG_UBSAN_SIGNED_WRAP: Die neue Version von Clang bereinigt Über- und Unterläufe von vorzeichenbehafteten Ganzzahlen trotz des Compiler-Flags -fwrapv. Das Flag -fwrapv ist dafür vorgesehen, vorzeichenbehaftete Ganzzahlen als Zweierkomplement-Ganzzahlen ohne Vorzeichen mit definiertem Überlaufverhalten zu behandeln.

      • Das Bereinigen von Überläufen mit Vorzeichen im Linux-Kernel kann helfen, Fehler zu erkennen. Es gibt jedoch Fälle, in denen ein Überlauf beabsichtigt ist, z. B. bei atomic_long_t. Daher wurde CONFIG_UBSAN_SIGNED_WRAP deaktiviert, damit UBSAN ausschließlich als Bounds-Sanitizer fungieren kann.
    • CONFIG_UBSAN_TRAP: UBSAN ist so konfiguriert, dass eine Kernel-Panik ausgelöst wird, wenn ein Problem erkannt wird, um die Integrität des Kernels zu schützen. Wir haben dieses Verhalten jedoch vom 23. Oktober bis zum 12. November deaktiviert. Wir haben das getan, um das Compiler-Update zu ermöglichen, während wir bekannte __counted_by-Probleme behoben haben.

1. November 2024

  • Linux 6.12-rc4
    • Zusammenfassung: CONFIG_OF_DYNAMIC kann möglicherweise zu schwerwiegenden Regressionen bei fehlerhaften Treibern führen.
    • Details: Beim Zusammenführen von Linux 6.12-rc1 in android-mainline sind Probleme mit dem Laden von Out-of-Tree-Treibern aufgetreten. Die Änderung, durch die die Treiberfehler aufgetreten sind, wurde als Commit 274aff8711b2 ("clk: Add KUnit tests for clks registered with struct clk_parent_data") identifiziert. Wir haben sie vorübergehend in aosp/3287735 rückgängig gemacht. Durch die Änderung wird CONFIG_OF_OVERLAY ausgewählt, wodurch CONFIG_OF_DYNAMIC ausgewählt wird. Mit !OF_DYNAMIC wird die Referenzzählung für of_node_get() und of_node_put() effektiv deaktiviert, da sie als noops implementiert sind. Durch die Aktivierung von OF_DYNAMIC werden wieder Probleme in Treibern sichtbar, die die Referenzzählung für struct device_node falsch implementieren. Dies führt zu verschiedenen Arten von Fehlern wie Speicherbeschädigung, Use-After-Free und Speicherlecks.
    • Alle Verwendungen von APIs, die mit der OF-Analyse zusammenhängen, müssen überprüft werden. Die folgende Liste ist unvollständig, enthält aber Fälle, die wir beobachtet haben:
      • Use-After-Free-Fehler (UAF):
        • Wiederverwendung desselben device_node-Arguments: Diese Funktionen rufen of_node_put() für den angegebenen Knoten auf. Möglicherweise muss vor dem Aufrufen ein of_node_get() hinzugefügt werden (z. B. beim wiederholten Aufrufen mit demselben Knoten als Argument):
          • 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()
        • Verwendung von device_node nach dem Beenden bestimmter Schleifen:
          • for_each_available_child_of_node_scoped()
          • for_each_available_child_of_node()
          • for_each_child_of_node_scoped()
          • for_each_child_of_node()
        • Direkte Zeiger auf char *-Attribute von device_node beibehalten, z. B. mit:
          • const char *foo = struct device_node::name
          • of_property_read_string()
          • of_property_read_string_array()
          • of_property_read_string_index()
          • of_get_property()
      • Speicherlecks:
        • device_node erhalten und vergessen, die Referenzierung aufzuheben (of_node_put()). Knoten, die von diesen zurückgegeben werden, müssen irgendwann freigegeben werden:
          • 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 aus einer Schleifeniteration beibehalten. Wenn Sie aus den folgenden Gründen zurückkehren oder abbrechen, müssen Sie die verbleibende Referenz irgendwann entfernen:
        • for_each_available_child_of_node()
        • for_each_child_of_node()
        • for_each_node_by_type()
        • for_each_compatible_node()
        • of_for_each_phandle()
    • Die oben erwähnte Änderung wurde beim Landen von Linux 6.12-rc4 (siehe aosp/3315251) wiederhergestellt, wodurch CONFIG_OF_DYNAMIC wieder aktiviert und möglicherweise fehlerhafte Treiber verfügbar gemacht werden.