
Локальный root-эксплойт для CVE-2025-21479 (Adreno KGSL) на iQOO Neo8 (SM8475) — чтение/запись физической памяти, отключает SELinux, запускает root-оболочку.
Код локального повышения привилегий для CVE-2025-21479, нацеленный на Qualcomm Adreno GPU (KGSL) на vivo V2301A (iQOO Neo8 / PD2301, Snapdragon 8+ Gen 1 / SM8475, Adreno A730, Android 14, ядро GKI 5.10).
В принципе, эксплуатация уязвимости через команду CP_SMMU_TABLE_UPDATE в KGSL управляет SMMU графического процессора,
получая возможность произвольного чтения и записи физической памяти, затем отключает SELinux, находит символы ядра и получает root
shell — на всём протяжении не требуется перепрошивка и не требуется разблокировка Bootloader.
Только для исследований безопасности на устройствах, которыми вы владеете или на которые у вас есть разрешение.
and $12, 0x3) имеет дефект, из-за которого пакет Self-Draw-State (SDS)
ошибочно распознаётся как RingBuffer (RB). Поэтому отправка поддельного CP_SMMU_TABLE_UPDATE в блок SDS
из пользовательского пространства позволяет перезаписать TTBR0 GPU, заставив таблицу страниц GPU указывать на произвольную физическую страницу — с этого момента GPU
может читать и записывать произвольную физическую память.stabilize_rw отображение закрепляется как 2 МБ самосопоставленная область,
что поддерживает быстрые массовые чтения (fast_pread_bytes и т. п.).selinux_state.enforcing в физической памяти.
Затем дамп образа ядра с фиксированного физического базового адреса 0xA8000000 (по умолчанию до 43 МБ) —
в SM8475 нет физического KASLR — и разбор структуры kallsyms напрямую из сырого дампа
(с автоопределением порядка байтов), поэтому виртуальный KASLR также не влияет.__do_sys_capset с помощью шелл-кода AArch64 (prepare_kernel_cred(0) →
commit_creds(), а также отключение seccomp). Дочерний процесс, созданный через fork,
вызывает capset() → становится uid 0 → восстанавливает перезаписанный код ядра → дочерний процесс
повторно выполняет указанную вами команду (по умолчанию sh) в домене u:r:shell:s0. Код ядра в итоге
побайтово совпадает с состоянием до запуска.| Модель | vivo V2301A (iQOO Neo8, кодовое имя PD2301, плата taro) |
| SoC | SM8475 (Snapdragon 8+ Gen 1) + Adreno 730 |
| Android | 14 (UP1A.231005.007, SDK 34, qssi-user) |
| Ядро | 5.10.198-gki-gfb2f5774872c |
| SELinux | Enforcing (отключается этим инструментом во время выполнения) |
Полная информация об устройстве см. в device_info.txt.
├── source/
│ ├── cheese.c # 漏洞利用主程序(include 了下面两个文件)
│ ├── kallsyms_lookup.c # 针对原始内核映像的 kallsyms 解析器
│ └── adrenaline.h # KGSL ioctl / 命令定义(作者 hawkes)
├── exploit # 预编译 arm64 二进制(动态链接,minSdk 21,
│ # NDK r30-beta2)
├── device_info.txt # 用于调参的目标设备信息
└── README.md
Примечание: cheese.c выполняет #include для kallsyms_lookup.c и adrenaline.h,
при компиляции все три файла должны находиться в одном каталоге.
Подойдёт любой достаточно новый Android NDK (r25+), пример:
# 静态链接(自包含、任意 API 等级可运行;体积较大)
aarch64-linux-android34-clang -o cheese source/cheese.c -static
# 动态链接(体积小,依赖设备自带的 libc;API 等级需匹配设备)
aarch64-linux-android34-clang -o exploit_dyn source/cheese.c
# 若要兼容 API 21+ 设备,请改用 aarch64-linux-android21-clang
#推送exploit
adb push exploit /data/local/tmp/
#运行exploit
adb shell
chmod +x /data/local/tmp/exploit
/data/local/tmp/exploit
Подробное руководство здесь (внутри есть инструмент «всё в одном»)
После успешного выполнения вы получите shell с uid=0, и SELinux в этой сессии будет отключён. После завершения повышения привилегий процесс повторно выполнит argv[1..] (по умолчанию sh). При каждом запуске будет обратный отсчёт ("pte wait 3 second") и индикатор прогресса чтения 43 МБ ядра ("Read X / 43 MB").

| Переменная | Назначение |
|---|---|
CHEESE_PHYADDR=<phys> | Принудительно задать физический базовый адрес ядра (пропустить встроенную таблицу обнаружения gPhyAddrs). |
CHEESE_ATTEMPT=<n> | Использовать gPhyAddrs[n] вместо gPhyAddrs[0]; после сбоя инициализации GPU maybe_retry автоматически увеличивает номер и повторяет попытку. |
CHEESE_SWAPPER_PG_DIR_OFF=<off> | Пропустить сканирование swapper_pg_dir и напрямую использовать указанное абсолютное смещение. |
CHEESE_READ_FULL_KERNEL=1 | Читать полный образ ядра (по умолчанию лимит чтения — DEFAULT_KERNEL_SIZE_MB = 43 МБ). |
CHEESE_KALLSYMS_MAX_MB=<MB> | Переопределить лимит чтения kallsyms. |
CHEESE_FORCE_MANUAL_PATCHFINDER=1 | Принудительно использовать ручной patchfinder как запасной вариант (init_cred, prepare_kernel_cred). |
CHEESE_SKIP_GPU=1 | Пропустить этап чтения/записи через GPU (только для отладки). |
CHEESE_NO_RETRY=1 | Завершиться сразу после сбоя, без повторных попыток с другим номером. |
Из-за особого механизма устройств vivo на iQOO Neo8 его необходимо отключить, чтобы стабильно сохранять root-права (конкретный принцип здесь не описывается. Для других моделей vivo и версий ядра это может не подходить — нужно самостоятельно извлечь vr.ko и провести обратный анализ). Перед выполнением следующих действий убедитесь, что текущая сессия shell уже получила root-права.
#备份原始apanic
dd if="$(readlink -f /dev/block/by-name/apanic)" of=/sdcard/apanic_full.bin
#adb shell内执行
adb pull /sdcard/apanic_full.bin ./
#主机端执行
#禁用vr.ko(风险自行评估)
printf '\370\037\000\000\000\000\000\000\000\000\000\000' | dd of=$(readlink -f /dev/block/by-name/apanic) bs=1 seek=$(( $(blockdev --getsize64 /dev/block/by-name/apanic) - 65472 )) conv=notrunc && sync
После этого, если холодная перезагрузка телефона приведёт к потере root-прав, достаточно повторно запустить exploit и снова выполнить джейлбрейк
$(find /data/app -type f -name "libksud.so" | grep resukisu) late-load --kmi android12-5.10
Константы, зависящие от устройства, находятся в верхней части source/cheese.c:
KERNEL_PHYS_BASE — физический базовый адрес ядра (по умолчанию 0xA8000000, SM8475)IDMAP_PG_DIR_OFFSET — смещение idmap_pg_dir (по умолчанию 0x245a000)selinux_state_offset — смещение для поиска selinux_state (по умолчанию
0x729030, фактический физический адрес = физический адрес idmap_pg_dir + это смещение)gPhyAddrs[] — список кандидатов физических базовых адресов, перебираемых по порядкуDEFAULT_KERNEL_SIZE_MB — резервное значение / верхний предел для чтения ядраПредварительные условия: GPU серии Adreno A730/A7xx (уязвимая прошивка), при этом на устройстве не установлен патч безопасности Qualcomm, выпущенный в июне 2025 года, в физическом дампе можно разобрать ядро с kallsyms, и отсутствует физический KASLR.