1 puntos por GN⁺ 2024-03-20 | 1 comentarios | Compartir por WhatsApp
  • CVE-2023-6241 es un error lógico en la unidad de administración de memoria de la GPU Arm Mali, que permite que una app maliciosa de Android llegue a ejecutar código arbitrario en el kernel y obtener privilegios root incluso en un Pixel 8 con MTE del kernel activado
  • Afecta a dispositivos recientes con GPU Arm Mali que usan Command Stream Frontend (CSF), incluidos Google Pixel 7 y Pixel 8
  • La vulnerabilidad funciona aprovechando una breve ventana en la que se libera un lock durante la expansión de memoria JIT, creando una inconsistencia entre los mapeos de GPU y el arreglo de backing pages
  • El exploit usa un mapeo de GPU restante hacia una backing page liberada, hace que esa página se reutilice como PGD del contexto de GPU y luego mapea memoria del kernel y código del kernel
  • MTE detecta discrepancias entre punteros y etiquetas de memoria, pero este flujo de ataque avanza fuera del alcance de protección de MTE porque la GPU accede directamente a direcciones físicas

Alcance de la vulnerabilidad y estado del parche

  • CVE-2023-6241 es una vulnerabilidad de la GPU Arm Mali que permite que una app maliciosa de Android obtenga ejecución de código arbitrario en el kernel y privilegios root en el dispositivo
  • Fue reportada a Arm el 15 de noviembre de 2023 y corregida en el driver Arm Mali r47p0, publicado el 14 de diciembre de 2023
  • La corrección de Android se incluyó en la actualización de seguridad de marzo de 2024
  • Afecta a dispositivos recientes con GPU Arm Mali que usan la función CSF (Command Stream Frontend); se citan como ejemplos Google Pixel 7 y Pixel 8
  • Se confirmó que el exploit funciona incluso con MTE del kernel activado en Pixel 8

Modelo de defensa de Arm64 MTE

  • MTE (Memory Tagging Extension) es una función de hardware de los procesadores Arm modernos que compara las etiquetas de punteros y bloques de memoria para detectar corrupción de memoria
  • Aunque los punteros Arm64 son de 64 bits, el espacio de direcciones real de las aplicaciones suele ser de 52 bits o menos, por lo que algunos bits superiores pueden usarse para almacenar etiquetas
  • En un desbordamiento lineal, la etiqueta de un bloque de memoria adyacente puede diferir de la etiqueta del puntero; en un use-after-free, puede producirse una discrepancia por el cambio de etiqueta durante la liberación y reasignación
  • A diferencia de mitigaciones de etapas posteriores como kCFI, MTE es una mitigación de etapa temprana que intenta detectar la corrupción de memoria en el momento en que ocurre por primera vez
  • Como la cantidad de bits de etiqueta es limitada, las colisiones son inevitables; aun usando solo etiquetas de 4 bits, la tasa de éxito aleatoria se reduce a 1/16
  • Si se filtran valores de punteros y bloques de memoria mediante ataques de canal lateral como Spectre, se puede eludir MTE acertando la etiqueta correcta, pero este tipo de filtraciones suelen estar al alcance de atacantes locales
  • Actualmente solo Google Pixel 8 permite activar MTE desde las opciones de desarrollador, y MTE viene desactivado por defecto
  • Para activar MTE en el kernel se requieren pasos adicionales

Carrera en la memoria JIT de Mali

  • Una app de usuario que usa el driver de la GPU Mali abre el archivo del driver y crea e inicializa el objeto de kernel kbase_context mediante llamadas ioctl
  • kbase_context administra varios tipos de memoria compartida entre el dispositivo GPU y la aplicación en espacio de usuario
  • Una región de memoria de la GPU Mali se representa como kbase_va_region; nr_pages indica el tamaño virtual y gpu_alloc->nents indica la cantidad real de backing pages
  • La memoria JIT es native memory cuyo ciclo de vida administra el driver del kernel, y la app asigna o libera memoria JIT mediante comandos de GPU
  • En las GPU CSF, los comandos de software y de hardware se colocan en colas distintas
    • Con KBASE_IOCTL_KCPU_QUEUE_CREATE se puede crear una kbase_kcpu_command_queue
    • Con KBASE_IOCTL_KCPU_QUEUE_ENQUEUE se encolan comandos
    • BASE_KCPU_COMMAND_TYPE_JIT_ALLOC y BASE_KCPU_COMMAND_TYPE_JIT_FREE se usan para asignar y liberar JIT
  • kbase_jit_allocate busca una región reutilizable en el pool de memoria JIT liberada y, si el tamaño físico no alcanza, aumenta las backing pages con kbase_jit_grow
  • kbase_jit_grow puede liberar temporalmente kctx->reg_lock y kctx->mem_partials_lock durante la llamada a kbase_mem_pool_grow
  • Como kctx->reg_lock protege el acceso concurrente a las regiones de memoria, el tramo en el que se libera el lock se convierte en una ventana de carrera

Flujo de activación de CVE-2023-6241

  • Si la GPU accede a una dirección de una región de memoria que no está respaldada por páginas físicas, se produce un fallo de acceso a memoria de GPU
  • kbase_mmu_page_fault_worker comprueba si la región puede crecer y luego puede asignar y mapear de inmediato las backing pages necesarias
  • Al crearse, una región JIT cumple las condiciones GROWABLE_FLAGS_REQUIRED, que incluyen KBASE_REG_PF_GROW y KBASE_REG_GPU_WR
  • La flag KBASE_REG_DONT_NEED, que se añade cuando se libera una región JIT, se elimina al inicio de kbase_jit_grow en kbase_mem_evictable_unmake
  • Como resultado, si durante la ventana de carrera de kbase_mem_pool_grow se genera un fallo de página de GPU sobre la misma región JIT, el manejador de fallos puede expandir esa región
  • Si el manejador de fallos cambia reg->gpu_alloc->nents, los valores old_size y delta guardados previamente por kbase_jit_grow dejan de coincidir con el estado real
  • Luego, kbase_alloc_phy_pages_helper_locked y kbase_mem_grow_gpu_mapping realizan la asignación de backing pages y el mapeo de GPU usando valores stale, lo que genera una inconsistencia entre el mapeo de GPU y el arreglo pages
  • Esta carrera es fácil de ganar porque kbase_mem_pool_grow incluye una asignación de memoria grande

Cómo cambió el ataque después del parche de GHSL-2023-005

  • En la vulnerabilidad anterior GHSL-2023-005, otro hilo podía reducir la región JIT con KBASE_IOCTL_MEM_COMMIT, invalidando old_size y delta
  • Después del parche de GHSL-2023-005, ya no es posible cambiar el tamaño de la memoria JIT con KBASE_IOCTL_MEM_COMMIT ioctl
  • En CVE-2023-6241, durante la ventana de carrera no se puede reducir la región, solo aumentarla
  • Si simplemente se aumenta, algunas de las últimas backing pages no quedan mapeadas en la GPU, pero el mapeo continuo desde el inicio se mantiene, por lo que no causa un problema inmediato
  • El exploit crea un nuevo mapeo detrás de un gap sin mapear mediante un fallo adicional de GPU y luego, al liberar el JIT, ajusta el punto de shrink dentro de ese gap para dejar un estado explotable

Suposición vulnerable al desmontar mapeos de GPU

  • kbase_mmu_teardown_pgd_pages recorre las tablas de páginas de GPU y marca entradas como inválidas para eliminar mapeos de direcciones de GPU
  • Esta función, si una PTE de nivel alto es inválida, asume que todo el rango grande de direcciones cubierto por esa entrada ya está unmapped y lo omite
  • Una PTE de nivel 2 cubre un rango de 512 páginas
  • En una kbase_va_region normal, las direcciones virtuales mapeadas siempre son continuas desde el inicio de la región y no tienen gaps intermedios, por lo que este comportamiento de omisión es seguro
  • El exploit de CVE-2023-6241 crea un gap sin mapear entre mapeos y ubica el punto inicial de shrink dentro de ese gap
  • kbase_mmu_teardown_pgd_pages encuentra una PTE inválida de nivel 2 y salta 512 páginas, pero algunas direcciones posteriores podrían estar realmente mapeadas
  • Las direcciones de GPU omitidas por error conservan el acceso a esas páginas físicas incluso después de liberar las backing pages

Proceso que lleva a la ejecución de código en el kernel

  • Al liberar la región JIT, se devuelven las backing pages, pero el mapeo de GPU que quedó por error puede seguir accediendo a las páginas liberadas
  • Las backing pages liberadas pueden reutilizarse luego como otras páginas del kernel
  • Una de las técnicas usadas consiste en hacer que una backing page liberada se reutilice como PGD (page table global directory) del kbase_context de GPU
  • La asignación de backing pages del driver Mali se realiza de forma jerárquica
    • Primero toma páginas del kbase_mem_pool del kbase_context actual
    • Si no alcanza, usa pool->next_pool
    • Si aun así no alcanza, asigna páginas directamente mediante el buddy allocator del kernel
  • pool->next_pool es un pool de memoria administrado por el driver Mali y compartido por todos los kbase_context, y también se usa para asignar PGD de contextos de GPU
  • Si una página liberada se reutiliza como PGD, la GPU puede volver a escribir ese PGD usando la dirección de GPU que quedó activa
  • Reescribir el PGD permite mapear memoria arbitraria del kernel y código del kernel en la GPU
  • En ese estado, es posible reescribir código del kernel para lograr ejecución de código arbitrario en el kernel, y leer y escribir datos del kernel para modificar credenciales de procesos y desactivar SELinux
  • El exploit para Pixel 8 y notas de configuración están publicados en el repositorio de GitHub Security Lab

Por qué se puede eludir MTE

  • Este flujo de exploit no requiere una etapa específica para eludir MTE
  • MTE detecta desreferenciaciones inválidas comprobando si coincide la etiqueta del bloque de memoria al que apunta un puntero
  • Al activar CVE-2023-6241, aparece una inconsistencia entre el arreglo pages y el mapeo de GPU, pero si se observa cada uno por separado, no hay ninguna entrada inválida
  • Cuando kbase_mmu_teardown_pgd_pages omite la eliminación del mapeo de GPU, la dirección física de la página de memoria liberada queda en la tabla de páginas de GPU
  • Cuando la GPU accede a esa página liberada, accede directamente a la dirección física, por lo que no pasa por una comprobación de desreferenciación de punteros
  • Tampoco está claro qué efecto tiene MTE sobre los accesos de memoria de la GPU
  • En consecuencia, este bug elude la protección de MTE aprovechando una ruta en la que la GPU, como coprocesador, accede directamente a la memoria física

Superficie de ataque que persiste incluso después de MTE

  • CVE-2023-6241 demuestra que incluso en un Pixel 8 con MTE del kernel activado, un solo bug puede alcanzar ejecución de código arbitrario en el kernel
  • MTE es un avance importante en mitigación de corrupción de memoria y puede volver inexplotables muchas vulnerabilidades de corrupción de memoria, pero no es una defensa universal
  • En este caso, la GPU elude MTE accediendo directamente a la memoria física
  • A medida que aumentan las mitigaciones de hardware y software del lado de la CPU, los coprocesadores y sus drivers de kernel pueden seguir siendo una superficie de ataque poderosa

1 comentarios

 
GN⁺ 2024-03-20
Opiniones de Hacker News
  • La clave aquí es que la GPU ha sido desde hace tiempo un dolor de cabeza para Android.
    La GPU tiene un acceso muy fuerte al AP, por lo que en la práctica puede eludir las mitigaciones implementadas delante. Los bugs en el código de mapeo del driver derivan en primitivas de ataque potentes, y se han explotado repetidamente en exploits reales en circulación. Al final, parece difícil que cambie mucho hasta que se rediseñe la arquitectura.

    • Creo que las GPU móviles a medio hacer deberían dejar de incorporar su propia MMU y usar una MMU de entrada/salida estándar.
    • ¿Qué significa AP aquí?
  • Lo interesante de esta vulnerabilidad es que es un bug lógico en la unidad de gestión de memoria de la GPU Arm Mali, y que puede eludir Memory Tagging Extension.
    Pero el resto del artículo parece explicar que la causa real es una condición de carrera, y que el uso después de liberar memoria es una consecuencia de eso.

  • ¿También habría afectado a instalaciones de GrapheneOS anteriores a la actualización de marzo?

    • Uno de los principales objetivos de GrapheneOS es distribuir actualizaciones de seguridad lo más rápido posible, así que si se corrigió upstream, casi seguro se incluyó en GrapheneOS.
      A veces adoptan niveles de parches de seguridad de AOSP antes del lanzamiento, o hacen backport de correcciones de seguridad de AOSP o del kernel que todavía no se publicaron.
    • Pensé que esto era un problema cercano al hardware dentro de la GPU, quizá relacionado con el firmware, así que supuse que seguiría afectando incluso después de la actualización de marzo. Esa actualización era sobre el stack de Bluetooth.
      Corrección: ignoren esto. Lo confundí con una publicación reciente del blog de GrapheneOS que decía “encontramos un problema por el cual MTE también se aplica a todas las apps del sistema”. GrapheneOS incorporó el “nivel completo de parches de seguridad 2024-03-05” en la versión 2024030600, así que parece que este parche también quedó incluido.
  • La seguridad de memoria probabilística de Arm MTE es un peldaño hacia el hardware determinista CHERI, https://saaramar.github.io/memory_safety_blogpost_2022/ y https://news.ycombinator.com/item?id=39668053
    Las mitigaciones correctas deben apuntar a la primitiva de ataque primaria, es decir, la causa raíz del bug. Como soluciones de hardware están CHERI(Morello, CheriIoT) y MTE; como mitigaciones de software están kalloc_type+dataPAC, AUTOSLAB, Firebloom, GuardedMemcpy, CastGuard y la reducción de la superficie de ataque; y como lenguajes de programación seguros están Rust y Swift. MTE y CHERI encajan bien y ayudan a eliminar desde la causa raíz los bugs de este tipo. MSR, MSRC y Azure Silicon impulsaron la reducción de CHERI hasta RISC-V32E, la especificación de núcleo RISC-V más pequeña
    Microsoft Research publicó como open source el stack de hardware/software CHERI para dispositivos IoT, https://msrc.microsoft.com/blog/2023/02/first-steps-in-cheri...
    Los microcontroladores basados en CHERI buscan lograr garantías de seguridad muy fuertes mediante el codiseño de la arquitectura de conjunto de instrucciones (ISA), la interfaz binaria de aplicaciones (ABI), el modelo de aislamiento y las partes centrales del stack de software. Estos microcontroladores logran mitigación determinista de la seguridad espacial mediante funciones CHERI-ISA; mitigación determinista de la seguridad temporal del heap y de la pila entre compartimentos mediante barreras de carga, puesta a cero, recuperación y control de flujo de información de 1 bit; y compartimentación fina mediante funciones CHERI-ISA adicionales y un monitor pequeño
    David Chisnall, U of Cambridge, https://lobste.rs/s/gnjx2n/c_can_be_memory_safe#c_9ohzku vía https://eclypsium.com/blog/a-faster-path-to-memory-safety-ch...
    “Hay unas 13 mil millones de líneas de código C/C++ open source que forman parte de varias bases de cómputo confiables, y la cifra crece si se incluye código propietario. Incluso si todo el mundo dejara de escribir C/C++ ahora y todos los ingenieros de software se enfocaran en reescribir el código legado en lenguajes seguros, reemplazarlo todo tomaría entre 5 y 10 años, y al sustituir código muy probado por código nuevo que requiere algoritmos y estructuras de datos diferentes para ajustarse a los modismos permitidos de los lenguajes seguros, es muy probable que también aparezcan muchos bugs lógicos.”
    “Si no se reescribe nada y solo se deja de escribir C/C++, con la tasa normal de reemplazo de código tomaría unos 50 años que las bases de cómputo confiables sean completamente seguras. Si no todos se ponen de acuerdo para dejar C/C++, serían al menos 100 años.”
    “En cambio, si los principales fabricantes de CPU lanzan CPU CHERI dentro de 5 años, entonces dentro de 15 años a partir de hoy la mayoría de las máquinas, especialmente las de alto valor, tendrán seguridad de memoria sin que los programadores cambien su comportamiento.”

    • Si te interesa CHERI para usos similares a embebidos/IoT, lowRISC está creando algunas plataformas de evaluación basadas en FPGA para CHERIoT: https://www.sunburst-project.org/
      La primera es el sistema Sonata: https://github.com/lowRISC/sonata-system. Consiste en una PCB dedicada con un FPGA, varios periféricos y headers. El diseño de la PCB ya está terminado y estará disponible a través de Mouser; incluso el layout de la placa es open source, así que también puedes ensamblarla por tu cuenta si quieres. Actualmente están trabajando en el RTL para el FPGA. Cuando esté listo, tendrás un sistema tipo microcontrolador basado en CHERIoT, con documentación y herramientas
      Además, también están creando el sistema Symphony, que combina Sonata con la raíz de confianza OpenTitan Earl Grey: https://github.com/lowRISC/symphony-system
    • También existe Solaris SPARC ADI. Debido al estado actual de Oracle y Solaris SPARC, casi todos lo tenemos olvidado, pero es una lástima
    • Como esto es un bug de hardware fuera de la CPU, no sé cómo ayudaría CHERI
      Además, la última vez que lo revisé, CHERI no era sound. Todavía se podían escribir bugs de memoria encima de él; ¿eso ya se corrigió?
    • “De 5 a 10 años para reemplazarlo todo” suena demasiado optimista si se habla en años
      Solo las discusiones de bike-shedding probablemente tomarían eso
    • El problema de fondo parece ser que el usuario ejecuta código malicioso y explota alguna colisión de hash de la MMU
      Este exploit probablemente se podría escribir en la mayoría de los lenguajes, incluido Rust
  • ¿El hardware es tan malo? Dios...

    • El hardware de GPU está lleno de bugs. Solo se vuelve a fabricar el hardware cuando el problema no se puede sortear en el driver a un costo aceptable
      Este enfoque es posible porque la GPU no permite un acceso relativamente directo al hardware como lo hace la CPU
    • Este es un bug del driver que se ejecuta en la CPU
  • Excelente investigación y artículo; me sorprende un poco, pero me alegra, que se haya publicado en el blog de GitHub.
    ¿Alguien sabe cuál es la “razón de negocio” de GitHub para hacer este tipo de investigación? No digo que necesariamente haga falta una razón de negocio, pero me sorprendió verlo aquí.

    • Man Yue Mo trabajó en Semmle antes de que GitHub la adquiriera (https://blog.sonatype.com/steps-to-responsible-disclosure, https://github.blog/2019-09-18-github-welcomes-semmle/)
      Esa función de investigación continuó como GitHub Security Lab. Semmle creó CodeQL, que ahora ofrece GitHub (https://docs.github.com/en/code-security/code-scanning/intro...). GitHub y Microsoft quieren asociar CodeQL con “información profunda de seguridad” (https://www.microsoft.com/en-us/security/blog/2023/11/02/ann...)
      Por eso siguen financiando investigaciones de seguridad novedosas como esta, y los profesionales de seguridad de la industria lo agradecen.
    • Este trabajo salió del Security Lab de GitHub: https://securitylab.github.com/
    • Con la adquisición por parte de Microsoft, obtuvieron los recursos para patrocinar este tipo de investigación.
      También existe la app de GitHub, y la seguridad de esa app no está fuera del alcance de GitHub. Si un atacante puede instalar una app oculta en un teléfono, puede hacer varias cosas haciéndose pasar por el usuario. Si se trata de alguien con influencia en GitHub, el daño podría ser bastante grande, así que encontrar este tipo de vulnerabilidades también beneficia a GitHub.
    • GitHub también tiene runners de Actions alojados para Arm.
      Por eso podrían estar interesados en revisar y validar las funciones de seguridad del hardware Arm para el sandboxing usando MTE.
    • En la práctica, lo veo más cercano a la investigación básica [0].
      En primera instancia, un producto como GitHub no necesariamente necesita expertos en seguridad de Android. Pero a largo plazo hay beneficios potenciales.
      [0]: https://en.wikipedia.org/wiki/Basic_research
  • Me sorprende que todavía no haya casos de CPUs y teléfonos con poca o ninguna GPU que se vendan como teléfonos de negocios.
    Las ventajas en seguridad, costo y consumo de energía parecen claras.

    • La desventaja obvia es que, al no tener una pantalla táctil de alta resolución, se volvería a algo como Blackberry o Palm Treo. De hecho, esos se vendían como teléfonos de negocios.