
Exploit del kernel de Android 14 para Pixel7/8 Pro
Este artículo proporciona un análisis en profundidad de dos vulnerabilidades del kernel en la GPU Mali, alcanzables desde el sandbox de aplicaciones predeterminado, que identifiqué y reporté de forma independiente a Google. Incluye un exploit del kernel que logra capacidades arbitrarias de lectura/escritura del kernel. En consecuencia, deshabilita SELinux y eleva los privilegios a root en los modelos Google Pixel 7 y 8 Pro con las siguientes versiones de Android 14:
google/husky/husky:14/UD1A.231105.004/11010374:user/release-keysgoogle/cheetah/cheetah:14/UP1A.231105.003/11010452:user/release-keysgoogle/cheetah/cheetah:14/UP1A.231005.007/10754064:user/release-keysgoogle/panther/panther:14/UP1A.231105.003/11010452:user/release-keys (por m4b4 (Marcel))Este exploit aprovecha dos vulnerabilidades: un desbordamiento de enteros resultante de un parche incompleto en el comando ioctl gpu_pixel_handle_buffer_liveness_update_ioctl, y una fuga de información en los búferes de mensajes del Timeline Stream.
Google abordó un desbordamiento de enteros en el comando ioctl gpu_pixel_handle_buffer_liveness_update_ioctl en este commit. Al principio, cuando reporté este problema, pensé que el error era causado por un problema en el parche descrito anteriormente. Tras revisar el informe, me di cuenta de que mi análisis de la vulnerabilidad era inexacto. A pesar de mi suposición inicial de que el parche estaba incompleto, en realidad resuelve y previene un subdesbordamiento en el cálculo. Esto me llevó a sospechar que el cambio no se había aplicado en las compilaciones de producción. Sin embargo, aunque puedo provocar un subdesbordamiento en el cálculo, no es posible provocar un desbordamiento. Esto sugiere que el comando ioctl se ha corregido parcialmente, aunque no con el parche mostrado anteriormente. Al examinar IDA se reveló que otra corrección incompleta se incluyó en las versiones de producción, y este parche no está presente en ninguna rama git del módulo del kernel de la GPU Mali.
Esta vulnerabilidad se descubrió por primera vez en la última versión de Android y se reportó el 19 de noviembre de 2023. Google me informó posteriormente de que ya la habían identificado internamente y le habían asignado el CVE-2023-48409 en el Boletín de seguridad de Android de diciembre, etiquetándola como un problema duplicado.
Aunque pude verificar que el error había sido identificado internamente meses antes de mi informe (según la fecha del commit, alrededor del 30 de agosto), sigue habiendo confusión. En concreto, es extraño que los niveles de parche de seguridad (SPL) de octubre y noviembre de los dispositivos más recientes siguieran afectados por esta vulnerabilidad —no he investigado versiones anteriores a estas. Por lo tanto, no puedo determinar de manera concluyente si realmente se trataba de un problema duplicado y si el parche correspondiente estaba efectivamente programado para diciembre antes de mi envío, o si hubo un descuido al abordar esta vulnerabilidad.
De todos modos, lo que hace poderosa esta vulnerabilidad es lo siguiente:
info.live_ranges está completamente controlado por el usuario.info.live_ranges pueda estar en un desplazamiento arbitrario anterior al comienzo de la dirección del kernel buff.Esta vulnerabilidad comparte similitudes con la vulnerabilidad de subdesbordamiento de búfer DeCxt::RasterizeScaleBiasData() que encontré y exploté en el kernel de iOS 15 en 2022.
La GPU Mali implementa un timeline stream personalizado diseñado para recopilar información, serializarla y, posteriormente, escribirla en un búfer circular siguiendo un formato específico. Los usuarios pueden invocar el comando ioctl kbase_api_tlstream_acquire para obtener un descriptor de archivo que les permita leer de este búfer circular. El formato de los mensajes es el siguiente:
Por ejemplo, la función __kbase_tlstream_tl_kbase_kcpuqueue_enqueue_fence_wait serializa los punteros del kernel kbase_kcpu_command_queue y dma_fence en el búfer de mensaje, lo que resulta en la fuga de punteros del kernel a procesos de espacio de usuario.```c
void __kbase_tlstream_tl_kbase_kcpuqueue_enqueue_fence_wait(
struct kbase_tlstream *stream,
const void *kcpu_queue,
const void *fence
)
{
const u32 msg_id = KBASE_TL_KBASE_KCPUQUEUE_ENQUEUE_FENCE_WAIT;
const size_t msg_size = sizeof(msg_id) + sizeof(u64)
+ sizeof(kcpu_queue)
+ sizeof(fence)
;
char *buffer;
unsigned long acq_flags;
size_t pos = 0;
buffer = kbase_tlstream_msgbuf_acquire(stream, msg_size, &acq_flags);
pos = kbasep_serialize_bytes(buffer, pos, &msg_id, sizeof(msg_id));
pos = kbasep_serialize_timestamp(buffer, pos);
pos = kbasep_serialize_bytes(buffer,
pos, &kcpu_queue, sizeof(kcpu_queue));
pos = kbasep_serialize_bytes(buffer,
pos, &fence, sizeof(fence));
kbase_tlstream_msgbuf_release(stream, acq_flags);
}
El exploit de prueba de concepto filtra la dirección del objeto `kbase_kcpu_command_queue` monitoreando el id de mensaje `KBASE_TL_KBASE_NEW_KCPUQUEUE`, que es despachado por la función `kbasep_kcpu_queue_new` cada vez que se asigna un nuevo objeto de cola kcpu.
Google me informó que la vulnerabilidad fue reportada en marzo de 2023 y se le asignó [CVE-2023-26083](https://source.android.com/docs/security/bulletin/2023-07-01) en su boletín de seguridad. No obstante, pude replicar el problema en los últimos dispositivos Pixel con los Niveles de Parche de Seguridad (SPL) de octubre y noviembre, lo que indica que la corrección no se había aplicado correctamente o no se había aplicado en absoluto. Posteriormente, Google abordó rápidamente el problema en el Boletín de Actualización de Seguridad de diciembre sin ofrecer crédito, y más tarde me informó que el problema se consideraba un duplicado. Sin embargo, la justificación para etiquetar este problema como duplicado sigue siendo cuestionable.
## Explotación
---
Así que tengo dos vulnerabilidades interesantes. La primera ofrece una potente capacidad para modificar el contenido de cualquier dirección del kernel alineada a 16 bytes que se encuentre antes de la dirección ~buff~ asignada. La segunda vulnerabilidad proporciona pistas sobre las posibles ubicaciones de objetos dentro de la memoria del kernel.