
Эксплойт ядра Android 14 для Pixel7/8 Pro
Эта статья предоставляет углубленный анализ двух уязвимостей ядра в Mali GPU, доступных из стандартной песочницы приложений, которые я самостоятельно выявил и сообщил в Google. Она включает эксплойт ядра, достигающий произвольного чтения/записи в ядро. Впоследствии он отключает SELinux и повышает привилегии до root на Google Pixel 7 и 8 Pro с указанными версиями 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 (от m4b4 (Marcel))Этот эксплойт использует две уязвимости: целочисленное переполнение из-за неполного исправления в ioctl-команде gpu_pixel_handle_buffer_liveness_update_ioctl, и утечку информации в буферах сообщений потока временной шкалы.
Google устранил целочисленное переполнение в ioctl-команде gpu_pixel_handle_buffer_liveness_update_ioctl в этом коммите. Сначала, когда я сообщил об этой проблеме, я думал, что ошибка вызвана проблемой в упомянутом патче. После анализа отчета я осознал, что мой анализ уязвимости был неточным. Несмотря на мое первоначальное предположение о неполноте патча, он эффективно устраняет и предотвращает недостаток в вычислениях. Это заставило меня заподозрить, что изменение не было применено в производственных сборках. Однако, хотя я могу вызвать недостаток в вычислениях, переполнение вызвать невозможно. Это предполагает, что ioctl-команда была частично исправлена, хотя и не с помощью указанного выше патча. Анализ в IDA показал, что в производственных релизах поставляется другой неполный патч, отсутствующий в любой ветке git модуля ядра Mali GPU.
Эта уязвимость была впервые обнаружена в последней версии Android и сообщена 19 ноября 2023 года. Google позже уведомил меня, что они уже внутренне идентифицировали её и присвоили CVE-2023-48409 в декабрьском бюллетене безопасности Android, пометив как дубликат. Хотя я смог проверить, что ошибка была внутренне идентифицирована за месяцы до моего отчета (исходя из даты коммита около 30 августа), остается неясность. В частности, странно, что уровни исправлений безопасности (SPL) за октябрь и ноябрь самых последних устройств все еще были подвержены этой уязвимости — я не исследовал версии, предшествующие этим. Поэтому я не могу окончательно определить, была ли это действительно дублирующаяся проблема и было ли соответствующее исправление запланировано на декабрь до моей подачи, или же было упущение в устранении этой уязвимости.
В любом случае, что делает эту ошибку мощной, так это следующее:
info.live_ranges полностью контролируется пользователем.info.live_ranges может находиться на произвольном смещении до начала адреса ядра buff.Эта уязвимость схожа с уязвимостью недостатка буфера DeCxt::RasterizeScaleBiasData(), которую я нашел и эксплуатировал в ядре iOS 15 в 2022 году.
GPU Mali реализует пользовательский поток временной шкалы, предназначенный для сбора информации, её сериализации и последующей записи в кольцевой буфер в определенном формате. Пользователи могут вызвать ioctl-команду kbase_api_tlstream_acquire, чтобы получить файловый дескриптор, позволяющий читать из этого кольцевого буфера. Формат сообщений следующий:
Сериализованный буфер сообщения, конкретное содержимое которого зависит от идентификатора сообщения.
Например, функция __kbase_tlstream_tl_kbase_kcpuqueue_enqueue_fence_wait сериализует указатели ядра kbase_kcpu_command_queue и dma_fence в буфер сообщения, что приводит к утечке указателей ядра в пользовательский процесс.```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); }
Доказательство концепции эксплуатации утечки адреса объекта `kbase_kcpu_command_queue` путем мониторинга идентификатора сообщения `KBASE_TL_KBASE_NEW_KCPUQUEUE`, который отправляется функцией `kbasep_kcpu_queue_new` при каждом выделении нового объекта очереди kcpu.
Google сообщил мне, что уязвимость была зарегистрирована в марте 2023 года и получила идентификатор [CVE-2023-26083](https://source.android.com/docs/security/bulletin/2023-07-01) в их бюллетене безопасности. Тем не менее, мне удалось воспроизвести проблему на новейших устройствах Pixel, поставляемых с уровнями исправлений безопасности (SPL) за октябрь и ноябрь, что указывает на то, что исправление не было применено правильно или вообще не было применено. Впоследствии Google быстро устранил проблему в декабрьском бюллетене обновлений безопасности, не указав автора, а позже сообщил мне, что проблема считается дубликатом. Однако обоснование, почему эту проблему пометили как дубликат, остается спорным.
## Эксплуатация
---
Итак, у меня есть две интересные уязвимости. Первая предоставляет мощную возможность изменять содержимое любого 16-байтового выровненного адреса ядра, который находится перед выделенным ~buff~ адресом. Вторая уязвимость дает подсказки о возможных местоположениях объектов в памяти ядра.
### Примечания к значениям buffer_count и live_ranges_count