Errata Android-mainline GKI 16-6.12

Cette page décrit les problèmes importants et les corrections de bugs détectés sur android-mainline qui peuvent être importants pour les partenaires.

15 novembre 2024

  • Clang est mis à jour vers la version 19.0.1 pour android-mainline et android16-6.12

    • Résumé: La nouvelle version de Clang introduit un outil de nettoyage des limites pour les tableaux, où la taille du tableau est stockée dans une variable distincte liée au tableau à l'aide de l'attribut __counted_by. Cette fonctionnalité peut provoquer une panique du noyau si la taille du tableau n'est pas correctement mise à jour. Le message d'erreur se présente comme suit:
    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 *[]')
    
    • Détails: Le nettoyeur de limites est essentiel pour protéger l'intégrité du noyau en détectant les accès hors limites. Lorsque CONFIG_UBSAN_TRAP est activé, le nettoyeur de limites déclenche une panique du noyau en cas de découverte.

      • La version précédente du nettoyeur de limites ne vérifiait que les tableaux de taille fixe et ne pouvait pas vérifier les tableaux alloués de manière dynamique. La nouvelle version utilise l'attribut __counted_by pour déterminer les limites du tableau au moment de l'exécution et détecter davantage de cas d'accès hors limite. Toutefois, dans certains cas, le tableau est accessible avant que la variable de taille ne soit définie, ce qui déclenche le nettoyeur de limites et provoque un plantage du kernel. Pour résoudre ce problème, définissez la taille du tableau immédiatement après avoir alloué la mémoire sous-jacente, comme illustré dans aosp/3343204.
    • À propos de CONFIG_UBSAN_SIGNED_WRAP: la nouvelle version de Clang assainit le débordement et le sous-dépassement des entiers signés malgré l'indicateur de compilation -fwrapv. L'indicateur -fwrapv est conçu pour traiter les entiers signés comme des entiers non signés en complément à deux avec un comportement de débordement défini.

      • Bien que la désinfection de l'excédent d'entiers signés dans le noyau Linux puisse aider à identifier les bugs, il existe des cas où l'excédent est intentionnel, par exemple avec atomic_long_t. Par conséquent, CONFIG_UBSAN_SIGNED_WRAP a été désactivé pour permettre à UBSAN de fonctionner uniquement en tant que nettoyeur de limites.
    • À propos de CONFIG_UBSAN_TRAP: UBSAN est configuré pour déclencher une panique du noyau lorsqu'il détecte un problème afin de protéger l'intégrité du noyau. Toutefois, nous avons désactivé ce comportement du 23 octobre au 12 novembre. Nous avons fait cela pour débloquer la mise à jour du compilateur pendant que nous corrigions les problèmes __counted_by connus.

1er novembre 2024

  • Lancement de Linux 6.12-rc4
    • Résumé: CONFIG_OF_DYNAMIC peut entraîner des régressions graves pour les pilotes défectueux.
    • Détails: lors de la fusion de 6.12-rc1 Linux dans android-mainline, nous avons constaté des problèmes de chargement des pilotes hors du noyau. La modification qui a exposé les bugs du pilote a été identifiée comme étant le commit 274aff8711b2 ("clk: Add KUnit tests for clks registered with struct clk_parent_data"). Nous l'avons temporairement annulée dans aosp/3287735. La modification sélectionne CONFIG_OF_OVERLAY, qui sélectionne CONFIG_OF_DYNAMIC. Avec !OF_DYNAMIC, le comptage des références sur of_node_get() et of_node_put() est effectivement désactivé, car ils sont implémentés en tant que noops. L'activation de OF_DYNAMIC expose à nouveau des problèmes dans les pilotes qui implémentent de manière incorrecte le comptage des références pour struct device_node. Cela entraîne divers types d'erreurs, telles que la corruption de la mémoire, l'utilisation après libération et les fuites de mémoire.
    • Toutes les utilisations des API liées à l'analyse OF doivent être inspectées. La liste suivante est partielle, mais contient les cas que nous avons observés :
      • Utilisation après libération (UAF) :
        • Réutilisation du même argument device_node: ces fonctions appellent of_node_put() sur le nœud donné et doivent peut-être ajouter un of_node_get() avant de les appeler (par exemple, lors d'appels répétés avec le même nœud comme 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()
        • Utilisation de device_node après tout type de sortie de certaines boucles :
          • for_each_available_child_of_node_scoped()
          • for_each_available_child_of_node()
          • for_each_child_of_node_scoped()
          • for_each_child_of_node()
        • Conserver des pointeurs directs vers les propriétés char * à partir de device_node, par exemple, à l'aide des éléments suivants :
          • const char *foo = struct device_node::name
          • of_property_read_string()
          • of_property_read_string_array()
          • of_property_read_string_index()
          • of_get_property()
      • Fuites de mémoire :
        • Obtenir un device_node et oublier de le désenregistrer (of_node_put()). Les nœuds renvoyés par ces éléments doivent être libérés à un moment donné :
          • 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()
      • Conserver un device_node à partir d'une itération de boucle. Si vous revenez ou interrompez l'exécution à partir des éléments suivants, vous devez supprimer la référence restante à un moment donné :
        • for_each_available_child_of_node()
        • for_each_child_of_node()
        • for_each_node_by_type()
        • for_each_compatible_node()
        • of_for_each_phandle()
    • Le changement mentionné précédemment a été restauré lors du déploiement de 6.12-rc4 Linux (voir aosp/3315251), ce qui a réactivé CONFIG_OF_DYNAMIC et potentiellement exposé des pilotes défectueux.