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 que podrían ser significativos para los socios.

15 de noviembre de 2024

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

    • Resumen: La nueva versión de Clang presenta un validador de límites para los arreglos, en el que el tamaño del arreglo se almacena en una variable independiente vinculada al arreglo 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 validador de límites es esencial para proteger la integridad del kernel, ya que detecta el acceso fuera de los límites. Además, con CONFIG_UBSAN_TRAP habilitado, el validador de límites activa un pánico del kernel en cualquier hallazgo.

      • La versión anterior del validador 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 validador de límites y causa un pánico del kernel. Para abordar 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 limpia el desbordamiento y el desbordamiento de números enteros firmados a pesar de la marca del compilador -fwrapv. La marca -fwrapv está diseñada para tratar números enteros con signo como números enteros sin signo de complemento de dos con comportamiento de desbordamiento definido.

      • Si bien la limpieza del desbordamiento de números enteros firmados 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 validador 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 desde el 23 de octubre hasta el 12 de noviembre. Hicimos esto para desbloquear la actualización del compilador mientras solucionábamos los problemas conocidos de __counted_by.

1 de noviembre de 2024

  • Lanzamiento de Linux 6.12-rc4
    • Resumen: CONFIG_OF_DYNAMIC puede causar regresiones graves en los controladores defectuosos.
    • Detalles: Mientras se fusionaba 6.12-rc1 de Linux en android-mainline, se observaron problemas con los controladores fuera del árbol que no se cargaban. El cambio que expuso los errores del controlador se identificó como confirmación 274aff8711b2 ("clk: Add KUnit tests for clks registered with struct clk_parent_data") y lo revirtieron 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. Si se habilita OF_DYNAMIC, nuevamente se exponen problemas en los controladores que implementan incorrectamente el recuento de referencias para struct device_node. Esto causa varios tipos de errores, como daños en la memoria, uso después de liberar y fugas 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 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 determinado y, posiblemente, deban agregar un of_node_get() antes de llamarlas (por ejemplo, cuando se llama de forma reiterada 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 char * de 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 anular su 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 haces una pausa desde lo siguiente, debes soltar 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()
    • Se restableció el cambio mencionado anteriormente cuando se implementó Linux 6.12-rc4 (consulta aosp/3315251), lo que volvió a habilitar CONFIG_OF_DYNAMIC y, potencialmente, expuso controladores defectuosos.