GKI 16-6.12 android-mainline errata

Auf dieser Seite werden wichtige Probleme und Fehlerkorrekturen beschrieben, die in android-mainline gefunden wurden und 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 der Grenzen erkennt. Wenn CONFIG_UBSAN_TRAP aktiviert ist, löst der Bounds-Sanitizer bei jedem Ergebnis eine Kernel Panic aus.

      • Die vorherige Version des Bounds-Sanitizers hat nur Arrays mit fester Größe geprüft und konnte dynamisch zugewiesene Arrays nicht prüfen. Die neue Version verwendet das Attribut __counted_by, um die Arraygrenzen zur Laufzeit zu ermitteln und mehr Fälle von Zugriffen außerhalb der Grenzen zu erkennen. In einigen Fällen wird jedoch auf das Array zugegriffen, bevor die Größenvariable festgelegt wird. Dadurch wird der Bounds-Sanitizer ausgelöst und es kommt zu einer Kernel Panic. Um dieses Problem zu beheben, legen Sie die Größe des Arrays sofort nach der Zuweisung des zugrunde liegenden Arbeitsspeichers fest, wie in aosp/3343204veranschaulicht.
    • Informationen 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 behandelt vorzeichenbehaftete Ganzzahlen als vorzeichenlose Ganzzahlen im Zweierkomplement mit definiertem Überlaufverhalten.

      • Das Bereinigen von Überläufen vorzeichenbehafteter Ganzzahlen im Linux-Kernel kann zwar helfen, Fehler zu finden, es gibt jedoch Fälle, in denen Überläufe beabsichtigt sind, z. B. bei atomic_long_t. Daher wurde CONFIG_UBSAN_SIGNED_WRAP deaktiviert damit UBSAN nur als Bounds-Sanitizer fungieren kann.
    • Informationen zu CONFIG_UBSAN_TRAP: UBSAN ist so konfiguriert, dass eine Kernel Panic ausgelöst wird, wenn ein Problem erkannt wird, um die Integrität des Kernels zu schützen. Dieses Verhalten wurde jedoch vom 23. Oktober bis zum 12. Novemberdeaktiviert. So konnte das Compiler-Update nicht blockiert werden, während wir bekannte __counted_by-Probleme behoben haben.

1. November 2024

  • Linux 6.12-rc4-Landing
    • Zusammenfassung: CONFIG_OF_DYNAMIC verursacht möglicherweise schwerwiegende Regressionen für fehlerhafte Treiber.
    • Details: Beim Zusammenführen von Linux 6.12-rc1 in android-mainline sind Probleme beim Laden von Treibern außerhalb des Baums aufgetreten. Die Änderung, die die Treiberfehler aufgedeckt hat, wurde als Commit 274aff8711b2 ("clk: Add KUnit tests for clks registered with struct clk_parent_data") identifiziert und wir haben sie in aosp/3287735 vorübergehend zurückgesetzt. Die Änderung wählt CONFIG_OF_OVERLAY aus, wodurch CONFIG_OF_DYNAMIC ausgewählt wird. Bei !OF_DYNAMIC wird die Referenzzählung für of_node_get() und of_node_put() effektiv deaktiviert, da sie als noops implementiert sind. Wenn OF_DYNAMIC wieder aktiviert wird, werden Probleme in Treibern aufgedeckt, 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 im Zusammenhang mit der OF-Analyse müssen geprüft werden. Die folgende Liste ist unvollständig, enthält aber Fälle, die wir beobachtet haben:
      • Use-After-Free (UAF):
        • Wiederverwendung desselben device_node-Arguments: Diese Funktionen rufen of_node_put() für den angegebenen Knoten auf. Möglicherweise muss vor dem Aufruf ein of_node_get() hinzugefügt werden (z. B. bei 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 *-Eigenschaften 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 abrufen und nicht freigeben (of_node_put()). Knoten, die von diesen Funktionen 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()
      • Beibehalten eines device_node aus einer Schleifeniteration. Wenn Sie innerhalb der folgenden Funktionen zurückkehren oder die Schleife verlassen, müssen Sie die verbleibende Referenz irgendwann freigeben:
        • 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 zuvor erwähnte Änderung wurde beim Landing von Linux 6.12-rc4 wiederhergestellt (siehe aosp/3315251) . Dadurch wurde CONFIG_OF_DYNAMIC wieder aktiviert und fehlerhafte Treiber wurden möglicherweise aufgedeckt.