
Исследование осуществимости 43499 (ghostlock) для PD2229B
| Параметр | Значение |
|---|---|
| Тип уязвимости | Use-After-Free на стеке в пути rt_mutex / futex PI |
| Версия внедрения | Linux 2.6.39-rc1 (май 2011, commit 8161239a8bcc) |
| Версия исправления | Основная ветка 7.1 (commit 3bfdc63936dd), стабильные ветки: 6.1.175 / 6.6.140 / 6.12.86 / 6.18.27 / 7.0.4 |
| Предусловия | CONFIG_FUTEX_PI=y (включено по умолчанию в основных ядрах) |
| CVSS | 7.8 High |
| Стабильность эксплуатации | Оригинальная цепочка NebuSec — 97%, получение root за ~5 секунд |
| Награда kernelCTF | $92,337 USD |
Затронутый диапазон ядер:
| Параметр | Значение |
|---|---|
| SoC | Qualcomm SM8475 (Snapdragon 8 Gen 1 Plus) |
| Версия ядра | 5.10.233-gki-g6e61de9f5b58 #1 SMP PREEMPT (24 ноября 2025) |
| Версия Android | 15 (OriginOS 5) |
| Время сборки | 25.11.2025 |
| Патчи Android | 01.11.2025 |
CONFIG_FUTEX_PI | y ✅ |
CONFIG_UNMAP_KERNEL_AT_EL0 | y (KPTI включен) |
kptr_restrict | enforced |
CONFIG_IO_URING | y ✅ (подтверждено символами vmlinux, seccomp не блокирует io_uring_setup) |
1. Обход KASLR → prefetch timing / PR_SET_MM_MAP auxv
2. Триггер UAF → взаимоблокировка трёх потоков PI → FUTEX_CMP_REQUEUE_PI возвращает -EDEADLK
3. Перехват стека → PR_SET_MM_MAP копирует auxv в стековый фрейм waiter
4. Ограниченная запись rb_erase → перезапись inet6_protos[IPPROTO_UDP]
5. CEA + ROP → перехват потока управления
6. Переключение core_pattern → root shell (97% успеха)
| Этап | Статус | Описание |
|---|---|---|
| 1. Обход KASLR | ✅ Реализовано | Побочный канал perf_event_open + выборка callchain (метод аналогичен адаптации для OPPO Find X6 Pro 5.15.149) |
| 2. Триггер UAF | ✅ Реализовано | Взаимоблокировка трёх потоков PI успешна, FUTEX_CMP_REQUEUE_PI возвращает -EDEADLK |
| 3. Примитив перехвата стека | ❌ Архитектурный провал | Стековые фреймы всех известных syscall не перекрываются с waiter (см. раздел 3) |
| 4. Ограниченная запись rb_erase | ❌ Заблокировано | Предусловия не выполнены |
| 5. Перезапись inet6_protos | ❌ Не начато | Зависит от этапа 4 |
| 6. ROP / перехват потока управления | ❌ Не начато | Зависит от этапа 5 |
| 7. root shell | ❌ Не начато | Зависит от этапа 6 |
Общая глубина пути futex:
__arm64_sys_futex 0x90
+ do_futex 0xc0
+ futex_wait_requeue_pi 0x1b0
= 0x300
Позиция waiter = SYS_SP - 0x300 + 0x20 = SYS_SP - 0x2e0
Путь pselect:
Стековый фрейм core_sys_select 0x1c0, stack_fds на sp+0x50
Область покрытия: начиная с SYS_SP - 0x1c0 + 0x50 = SYS_SP - 0x170
Расстояние до waiter (SYS_SP - 0x2e0) = 0x170 (368 байт) → перекрытия нет
| # | Метод | Системный вызов | Результат на PD2229 | Основная причина неудачи |
|---|---|---|---|---|
| 1 | stamp_prctl | PR_SET_MM_MAP | ❌ EPERM | Жёсткая блокировка Android |
| 2 | stamp_pselect | pselect6 (NFDS=320) | ❌ Нет перекрытия | waiter на 120 Б ниже fd_set |
| 3 | stamp_pselect | pselect6 (NFDS>336) | ❌ Выделение в куче | Путь kvmalloc |
| 4 | stamp_socket | MCAST_JOIN_SOURCE_GROUP | ❌ Недостаточное покрытие | Записывается только поле lock |
| 5 | stamp_sendmsg | sendmsg | ❌ 80 Б до waiter | Глубина фрейма 0x90 недостаточна |
| 6 | stamp_sendmmsg | sendmmsg | ❌ 112 Б до waiter | Фрейм недостаточен |
| 7 | stamp_recvmmsg | recvmmsg | ❌ Обнуляет task/lock | Фрейм 0x1d0 повреждает критические указатели |
| 8 | stamp_process_vm | process_vm_writev | ❌ Нет перекрытия | Стек дочернего потока выделяется отдельно |
| 9 | stamp_keyctl | KEYCTL_INSTANTIATE_IOV | ❌ EOPNOTSUPP | Системный вызов не поддерживается + фрейм 0x40 |
| 10 | stamp_tcp | TCP_ZEROCOPY_RECEIVE | ❌ Фрейм недостаточен | Предполагаемая глубина мала |
| 11 | stamp_futex | Рекурсия FUTEX_CMP_REQUEUE_PI | ❌ Логически невозможно | Разрушает окно UAF |
| 12 | binder ioctl | BINDER_WRITE_READ | ❌ EACCES | Нет прав на /dev/binder у shell |
| 13 | poll | poll | ❌ Выделение в куче | pollfd в куче |
| 14 | epoll_wait | epoll_wait | ❌ Фрейм слишком мелкий | Фрейм 0xE0 |
| 15 | sched_setattr | sched_setattr | ❌ Недостаточная глубина | Фрейм 0xb0 |
| 16 | timerfd_settime | timerfd_settime | ❌ Нет копирования в стек | Нет большого стекового буфера |
| 17 | io_uring_register | IORING_REGISTER_* | ❌ Двойной провал | ①Фрейм всего 0xF0, цель copy_from_user фиксирована на sp+0x8 (разница 424 байта с sp+0x1D0 у waiter); ②хотя io_uring_setup не блокируется seccomp (возвращает EFAULT, а не ENOSYS), раскладка стека не совпадает |
17/17 — все неудачны.
Раскладка стека, созданная компилятором для SM8475 5.10 GKI на PD2229 (PGO + LTO + BOLT), приводит к тому, что stack_fds в core_sys_select и rt_mutex_waiter в futex_wait_requeue_pi архитектурно не перекрываются. Это объективный факт, определяемый компилятором, а не проблема техники эксплуатации.
В репозитории JoinChang прямо указано: "The pselect stack overlay only works when the freed rt_mutex_waiter lands within the user-controllable region of the stack_fds buffer" — PD2229 не удовлетворяет этому условию.
PR_SET_MM_MAP копирует auxv в стек ядраPR_SET_MM_MAP блокируется на Android через EPERMPSELECT_SHIFT = -2