
GhostLock (CVE-2026-43499) — эксплойт для ядра Android-устройств с заблокированным загрузчиком
Эксплойт ядра для Android-устройств с заблокированным загрузчиком. Обеспечивает временный root + установку KernelSU без разблокировки загрузчика или изменения boot-образа. Автоматическое определение версии ядра во время выполнения с таблицей смещений для нескольких устройств.
CVE-2026-43499 — Futex PI (Priority Inheritance) Use-After-Free
Затрагивает ядро Linux 5.7 ~ 7.1. Исправлено в стабильных версиях 6.1.175, 6.6.140, 6.12.86. Большинство Android-устройств остаются незапатченными по состоянию на сентябрь 2026 года.
Сисколл pselect6 копирует данные fd_set в стек ядра. В сочетании с механизмом ожидания futex PI освобождённый стековый кадр может быть переиспользован как структура rt_mutex_waiter. Перебалансировка rb-tree во время обхода цепочки PI затем записывает управляемые значения в произвольные адреса ядра.
Наложение стека pselect требует, чтобы освобождённый rt_mutex_waiter попал в управляемую пользователем область stack_fds (слова 0–14). Место его попадания определяется профилями PGO/LTO компилятора, а не версией ядра. См. Расположение стека.
Примечание о реализуемости 6.1: Ядра OPLUS 6.1 стабильно нереализуемы из-за инлайнинга
do_futexчерез PGO. Однако некоторые не-OPLUS ядра 6.1 (vivo) сохраняют стандартную цепочку вызовов и реализуемы (vivo T4, X Fold3 Pro). Реализуемость необходимо проверять для каждого устройства отдельно.
Два пути получения root, выбираются автоматически на основе возможностей устройства:
Требует off_ashmem_misc_fops != 0 (C ashmem со статическим miscdevice в BSS).
PI write (mode=4) → перенаправление fops miscdevice на поддельные fops
→ configfs r/w → pipe physrw (точный r/w ядра с точностью до 1 байта)
→ SELinux enforcing = 0 (один байт, без повреждения policycap)
→ UMH: инъекция work_struct в system_unbound_wq
→ root-скрипт → ksud late-load → KSU установлен
Доступно на: OnePlus 13, OPPO Pad 4 Pro, устройствах с C ashmem 5.10/6.1. Недоступно на Rust ashmem (6.12 GKI) — miscdevice с heap-аллокацией.
Write 1 (mode=1) → SELinux enforcing = 0 (8-байтовая запись, повреждает соседние байты)
Write 2 (mode=2) → task->cred = init_cred (uid=0, все capabilities)
Root-шелл → ksud late-load → KSU → исправление политики SELinux
После W1+W2 эксплойт патчит поле config в бинарнике политики SELinux (|= 0xC0000000 для ANDROID_NETLINK_ROUTE + GETNEIGH) и перезагружает её через /sys/fs/selinux/load для восстановления сетевого подключения.
App (seccomp) → Write 1 → mini-adb TCP → adb shell: полный эксплойт → root
Загрузчик при запуске предоставляется отдельным приложением GhostLock Anchor.
При NFDS=320 функция core_sys_select выделяет 256-байтовый буфер stack_fds в стеке ядра:
stack_fds: 0 5 10 14 | 15 20 25 29
├─in─┤─out─┤─ex──┤ ├res_in┤res_out┤res_ex┤
◄── USER CONTROLLED ──►│◄── KERNEL ZEROED ──►
Эксплойт размещает поддельные поля waiter (task, lock) во входных битовых картах fd_set. Для вложенного waiter 6.12 (14 слов): максимальное реализуемое слово waiter = 3. Для компактного waiter 5.10/6.1 (10 слов): максимальное реализуемое слово waiter = 7.
Позиция waiter зависит от глубины цепочки вызовов:
Все записи в ядро используют алиас линейной карты. Загрузчик выбирает kernel_phys_load, который различается для каждого SoC:
| SoC | kernel_phys_load |
|---|---|
| SM8845 (Ace 6T, 15T) | 0xa8000000 |
| SM8750 (OnePlus 13, OPPO Pad 4 Pro) | 0xa8000000 |
Неверное значение приводит к тихому сбою. Прочитайте его на устройстве с root:
su -c 'grep -i "Kernel code" /proc/iomem' # c7810000-... → 0xc7800000
Переопределение во время выполнения: KPHYS=0xc7800000 /data/local/tmp/a/e
/data/local/tmp/a/e # По умолчанию (shift=0)
PSELECT_SHIFT=-2 /data/local/tmp/a/e # OnePlus 13 (6.6)
Ядра 5.10 используют 0xffffffc008000000 (VA_BITS=39, отличается от значения по умолчанию для 6.x 0xffffffc080000000). Это обрабатывается автоматически через поле kimage_text_base в записи смещений устройства.
make NDK_ROOT=/path/to/android-ndk
Или напрямую:
NDK=/path/to/android-ndk
"$NDK/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android35-clang" \
-O2 -Wall -Isrc/core -Isrc/devices -DTARGET_CONFIG_H=\"target.h\" \
src/core/main.c src/core/util.c src/core/slide.c \
src/core/fops.c src/core/pipe_physrw.c src/core/root.c \
src/core/miniadb.c src/core/umh_root.c \
-o ./ghostlock -fPIE -pie -pthread
GhostLock предоставляет временный root. Установка KernelSU требует ksud, который включает kernelsu.ko для каждой версии KMI.
| Метод | Шаги |
|---|---|
| APK ReSukiSU (рекомендуется) | Установите ReSukiSU или этот . Включает . |
adb shell mkdir -p /data/local/tmp/a
adb push ./ghostlock /data/local/tmp/a/e
adb shell chmod 755 /data/local/tmp/a/e
adb shell /data/local/tmp/a/e
Запускайте после завершения загрузки и готовности ADB.
Нужен только boot.img — root или доступ к устройству не требуются.
См. руководство по инструментам kallsyms для полного рабочего процесса, или:
python tools/extract_target.py --kallsyms kallsyms.txt
python tools/extract_btf.py kernel
Проверьте, инлайнит ли PGO do_futex, выполнив поиск в бинарнике ядра всех инструкций ветвления, нацеленных на futex_wait_requeue_pi. Если __arm64_sys_futex вызывает её напрямую (в обход do_futex), устройство, скорее всего, нереализуемо.
Добавьте src/devices/<name>/offsets.h с извлечёнными смещениями и включите его в src/devices/offsets.h. Используйте соответствующий макрос смещений структур:
Для устройств с компактным waiter 5.10/6.1 также установите .kimage_text_base=0xffffffc008000000ULL.
Только для авторизованных исследований в области безопасности и образовательных целей.
| Устройство | SoC | Ядро | Ветка GKI | SHIFT |
|---|
| OnePlus Ace 6T (PLR110) | SM8845 | 6.12.38 | android16-5 | 0 |
| OnePlus 15 (CPH2745/2747/2749) | SM8850 | 6.12.23 | android16-5 | 0 |
| Xiaomi 17 (pudding) | SM8850 | 6.12.23 / 6.12.69 | android16-5 / android16-6 | 0 |
| OnePlus 13 (IN2060) | SM8750 | 6.6.89 | android15-8 | -2 |
| OPPO Pad 4 Pro | SM8750 | 6.6.89 | android15-8 | -2 |
| Устройство | SoC | Ядро | Примечания |
|---|
| OnePlus 15T (PLZ110) | SM8845 | 6.12.38 | То же ядро, что и Ace 6T |
| OPPO Reno10 Pro+ (CPH2521) | SM8475 | 5.10.236 | Компактный waiter 5.10, waiter word=0 |
| Vivo X Fold3 Pro (PD2337) | SM8650 | 6.1.124 | Компактный waiter 6.1, waiter word=3 |
| Vivo T4 | SM8650 | 6.1.145 | Компактный waiter 6.1, waiter word=3 |
| Устройство | SoC | Ядро | Корневая причина |
|---|
| OPPO Find X9 Ultra | SM8750 | 6.12.58 | PGO устраняет do_futex → waiter word=14 |
| OnePlus 12 | SM8650 | 6.1.141 | PGO инлайнит do_futex → waiter word=13/19 |
| OnePlus 13R / Ace 5 | SM8650 | 6.1.x | OPLUS 6.1: waiter word=13 |
| realme RMX5070 | SM6650 | 6.1.141 | OPLUS 6.1: waiter word=13 |
| OPPO Pad 5 (OPD2502) | MT6878 | 6.1.134 | OPLUS 6.1: waiter word=13 |
| Motorola Edge 60 Fusion | MT6878 | 6.1.145 | Не-OPLUS 6.1: тот же результат |
| iQOO Neo 10 CN | SM8650 | 6.1.84 | Кадр do_futex 0xD0 → waiter word=-11 |
| OPPO PKW110 | — | 5.15.180 | Кадр do_futex 0x140 → waiter word=-29 |
| iQOO Z9 5G | — | 5.15.178 | Кадр do_futex слишком большой |
| CPH2763 (OPPO) | — | 6.1.115 | OPLUS 6.1: PGO инлайнит, waiter word=24 |
| Паттерн | Цепочка вызовов | Реализуемо |
|---|
| android16-5 (6.12) | sys_futex → do_futex → fwrpi | ✅ waiter word=2 |
| android15-8 (6.6) | sys_futex → do_futex → fwrpi | ✅ waiter word=2 (SHIFT=-2) |
| vivo 6.1 | sys_futex → do_futex → fwrpi | ✅ waiter word=3 |
| OPLUS 6.1 | sys_futex → fwrpi (PGO инлайнит) | ❌ waiter word=13+ |
| android16-6 (X9 Ultra) | sys_futex → fwrpi (PGO инлайнит) | ❌ waiter word=14 |
| 5.10 OPLUS | sys_futex → do_futex → fwrpi | ✅ waiter word=0 |
| SM8650 (vivo T4, X Fold3 Pro) |
0xa8000000 |
| SM8850 (OnePlus 15, Xiaomi 17) | 0xc7800000 |
libksud.so| CI-релиз | Скачайте с ReSukiSU CI |
| Ядро | Расположение waiter | Макрос |
|---|
| 6.12.x | Вложенный (14 слов) | STRUCT_OFFSETS_6_12 |
| 6.6.x | Вложенный (14 слов) | STRUCT_OFFSETS_6_6 |
| 6.1.x (vivo) | Компактный (10 слов) | STRUCT_OFFSETS_6_1 |
| 5.10.x | Компактный (10 слов) | STRUCT_OFFSETS_5_10 |
| Файл | Описание |
|---|
src/core/main.c | Точка входа эксплойта, W1/W2, путь UMH, bootstrap, root-скрипт, исправление политики SELinux |
src/core/fops.c | Маршрут pselect, PI write, этап CFI, поддержка компактного waiter |
src/core/util.c | Heap spray, KernelSnitch, слив slab, настройка payload |
src/core/pipe_physrw.c | Чтение/запись физической памяти через буфер pipe |
src/core/umh_root.c | UMH root через инъекцию workqueue |
src/core/miniadb.c | Мини-клиент ADB (TCP + RSA-аутентификация) |
src/core/target.h | Расположение памяти, значения полей структур по умолчанию (6.12) |
src/core/runtime_struct_offsets.h | Переопределение полей структур для конкретного устройства |
src/devices/offsets.h | Таблицы смещений устройств + макросы STRUCT_OFFSETS_* |
tools/extract_target.py | Извлечение смещений из kallsyms |
tools/extract_btf.py | Извлечение смещений структур из BTF |
tools/kallsyms/ | Полный рабочий процесс восстановления kallsyms |