GKI 16-6.12 android-mainline errata

Auf dieser Seite werden wichtige Probleme und Fehlerkorrekturen beschrieben, die bei 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 Grenzwert-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-Panik 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 wichtig, 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 jeder gefundenen Abweichung einen Kernel-Panik aus.

      • Die vorherige Version des Grenzwert-Sanitizers überprüfte nur Arrays mit fester Größe und konnte dynamisch zugewiesene Arrays nicht prüfen. 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 Gültigkeitsbereichs zu erkennen. In einigen Fällen wird jedoch auf das Array zugegriffen, bevor die Variable „size“ festgelegt wurde. Dies löst den Grenzwert-Sanitizer aus und führt zu einer Kernel-Panik. Legen Sie die Größe des Arrays direkt nach der Zuweisung des zugrunde liegenden Arbeitsspeichers fest, wie in aosp/3343204 dargestellt.
    • CONFIG_UBSAN_SIGNED_WRAP: Die neue Version von Clang behebt trotz des Compiler-Flags -fwrapv Über- und Unterlauf von signed integer. Das Flag -fwrapv ist so konzipiert, dass vorzeichenbehaftete Ganzzahlen als vorzeichenlose Ganzzahlen im Zweierkomplement mit definiertem Overflow-Verhalten behandelt werden.

      • Das Entfernen von Überläufen bei signed integer im Linux-Kernel kann zwar dazu beitragen, Fehler zu identifizieren, es gibt aber Fälle, in denen ein Überlauf beabsichtigt ist, z. B. bei atomic_long_t. Daher wurde CONFIG_UBSAN_SIGNED_WRAP deaktiviert, damit UBSAN nur als Grenzwert-Sanitizer verwendet werden kann.
    • CONFIG_UBSAN_TRAP: UBSAN ist so konfiguriert, dass ein 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. November deaktiviert. Dadurch konnten wir das Compiler-Update freischalten, während wir bekannte __counted_by-Probleme behoben haben.

1. November 2024

  • Linux 6.12-rc4 veröffentlicht
    • Zusammenfassung: CONFIG_OF_DYNAMIC kann bei fehlerhaften Treibern zu schwerwiegenden Rückschritten führen.
    • Details: Beim Zusammenführen von Linux 6.12-rc1 mit android-mainline haben wir Probleme festgestellt, bei denen nicht im Stamm enthaltene Treiber nicht geladen werden konnten. 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 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 ist 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, treten Probleme in Treibern auf, 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 zum Parsen von OF-Dateien 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() auf dem angegebenen Knoten auf und müssen vor dem Aufruf möglicherweise eine of_node_get() hinzufügen (z. B. bei wiederholtem Aufruf 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 jeder Art von Beendigung 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 Verweise auf char *-Properties aus 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 vergessen, die Referenz aufzuheben (of_node_put()). Die von diesen zurückgegebenen Knoten 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 von einem der folgenden Elemente aus zurückkehren oder eine Unterbrechung einfügen, müssen Sie die verbleibende Referenz irgendwann löschen:
        • 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 Einspielen von Linux 6.12-rc4 (siehe aosp/3315251) wiederhergestellt, wodurch CONFIG_OF_DYNAMIC wieder aktiviert wurde und möglicherweise fehlerhafte Treiber auftraten.