Errata de android-mainline de GKI 16-6.12

En esta página, se describen los problemas importantes y las correcciones de errores que se encontraron en android-mainline y que podrían ser significativos para los socios.

15 de noviembre de 2024

  • Se actualizó Clang a la versión 19.0.1 para android-mainline y android16-6.12

    • Resumen: La nueva versión de Clang introduce un verificador de límites para los arrays, en el que el tamaño del array se almacena en una variable independiente vinculada al array con el atributo __counted_by. Esta función puede causar un error irrecuperable del kernel si el tamaño del array no se actualiza correctamente. El mensaje de error se ve de la siguiente manera:
    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 *[]')
    
    • Detalles: El sanitizador de límites es esencial para proteger la integridad del kernel, ya que detecta los accesos fuera de los límites. Además, con CONFIG_UBSAN_TRAP habilitado, el sanitizador de límites activa un error de kernel ante cualquier hallazgo.

      • La versión anterior del verificador de límites solo verificaba arrays de tamaño fijo y no podía verificar arrays asignados de forma dinámica. La nueva versión usa el atributo __counted_by para determinar los límites del array en el tiempo de ejecución y detectar más casos de acceso fuera de los límites. Sin embargo, en algunos casos, se accede al array antes de que se establezca la variable de tamaño, lo que activa el filtro de límites y provoca un error grave del kernel. Para solucionar este problema, establece el tamaño del array inmediatamente después de asignar la memoria subyacente, como se ilustra en aosp/3343204.
    • Acerca de CONFIG_UBSAN_SIGNED_WRAP: La nueva versión de Clang corrige el desbordamiento y el subdesbordamiento de números enteros firmados a pesar de la marca -fwrapv del compilador. La marca -fwrapv está diseñada para tratar los números enteros con signo como números enteros sin signo de complemento a dos con un comportamiento de desbordamiento definido.

      • Si bien la sanitización del desbordamiento de números enteros con signo en el kernel de Linux puede ayudar a identificar errores, hay casos en los que el desbordamiento es intencional, por ejemplo, con atomic_long_t. Como resultado, CONFIG_UBSAN_SIGNED_WRAP se inhabilitó para permitir que UBSAN funcione únicamente como un verificador de límites.
    • Acerca de CONFIG_UBSAN_TRAP: UBSAN está configurado para activar un error irrecuperable del kernel cuando detecta un problema para proteger la integridad del kernel. Sin embargo, inhabilitamos este comportamiento del 23 de octubre al 12 de noviembre. Hicimos esto para desbloquear la actualización del compilador mientras corregíamos los problemas conocidos de __counted_by.

1 de noviembre de 2024

  • Lanzamiento de Linux 6.12-rc4
    • Resumen: CONFIG_OF_DYNAMIC podría causar regresiones graves para los controladores defectuosos.
    • Detalles: Mientras fusionábamos Linux 6.12-rc1 en android-mainline, notamos problemas con los controladores externos que no se cargaban. El cambio que expuso los errores del controlador se identificó como la confirmación 274aff8711b2 ("clk: Add KUnit tests for clks registered with struct clk_parent_data") y lo revertimos temporalmente en aosp/3287735. El cambio selecciona CONFIG_OF_OVERLAY, que selecciona CONFIG_OF_DYNAMIC. Con !OF_DYNAMIC, el recuento de referencias en of_node_get() y of_node_put() se inhabilita de manera efectiva, ya que se implementan como noops. Habilitar OF_DYNAMIC nuevamente expone problemas en los controladores que implementan incorrectamente el recuento de referencias para struct device_node. Esto provoca varios tipos de errores, como corrupción de memoria, uso después de liberar y pérdidas de memoria.
    • Se deben inspeccionar todos los usos de las APIs relacionadas con el análisis de OF. La siguiente lista es parcial, pero contiene los casos que hemos observado:
      • Uso tras la liberación (UAF):
        • Reutilización del mismo argumento device_node: Esas funciones llaman a of_node_put() en el nodo proporcionado, por lo que es posible que deban agregar un of_node_get() antes de llamarlas (por ejemplo, cuando se llama repetidamente con el mismo nodo como argumento):
          • 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()
        • Uso de device_node después de cualquier tipo de salida de ciertos bucles:
          • for_each_available_child_of_node_scoped()
          • for_each_available_child_of_node()
          • for_each_child_of_node_scoped()
          • for_each_child_of_node()
        • Mantener punteros directos a las propiedades de char * desde device_node, por ejemplo, con lo siguiente:
          • const char *foo = struct device_node::name
          • of_property_read_string()
          • of_property_read_string_array()
          • of_property_read_string_index()
          • of_get_property()
      • Fugas de memoria:
        • Obtener un device_node y olvidarse de quitarle la referencia (of_node_put()). Los nodos que se devuelven de estos deben liberarse en algún momento:
          • 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()
      • Mantener un device_node de una iteración de bucle Si regresas o interrumpes la ejecución dentro de lo siguiente, debes descartar la referencia restante en algún momento:
        • for_each_available_child_of_node()
        • for_each_child_of_node()
        • for_each_node_by_type()
        • for_each_compatible_node()
        • of_for_each_phandle()
    • El cambio mencionado anteriormente se restableció mientras se incorporaba Linux 6.12-rc4 (consulta aosp/3315251), lo que habilitó CONFIG_OF_DYNAMIC nuevamente y, posiblemente, expuso controladores defectuosos.