
CVE-2026-43499 exploit de root GhostLock para Chromecast com Google TV (sabrina)
Exploit de root para Chromecast com Google TV (sabrina) via CVE-2026-43499 -- um use-after-free no subsistema futex PI (herança de prioridade) do kernel Linux.
Obtém root em um dispositivo com bootloader bloqueado executando Android 14 com kernel 5.15.170 (PGO+BOLT+LTO, clang 17).
O GhostLock explora um bug em remove_waiter() chamado a partir do caminho de rollback -EDEADLK em rt_mutex_start_proxy_lock(). A função limpa current->pi_blocked_on (o do requeuer, já NULL) em vez do da tarefa waiter. O pi_blocked_on do waiter nunca é limpo, deixando um ponteiro pendente para um rt_mutex_waiter liberado na pilha do kernel.
Um sched_setattr subsequente dispara rt_mutex_adjust_pi -> rt_mutex_adjust_prio_chain, que segue o ponteiro pendente e percorre uma cadeia PI sobre dados controlados pelo atacante em uma página de heap reocupada -- fornecendo uma primitiva de escrita arbitrária via rb_erase.
| Estágio | Técnica |
|---|---|
| Vazamento de KASLR | perf_event_open com PERF_SAMPLE_IP (condicionado por TID) — o IP mínimo do kernel está em .entry.text (+0x10000), _text é alinhado a 2MB e o deslocamento KASLR é um múltiplo de 2MB, então min_ip & ~0x1fffff recupera exatamente o _text em tempo de execução |
| Vazamento de task struct | perf_event_open com PERF_SAMPLE_REGS_INTR (condicionado por TID, modo de endereços do mapa linear) |
| Validação da tabela de símbolos | perf-samples de &init_user_ns a partir dos argumentos de registro de security_capable() durante uma tempestade de setpriority(-20) e compara com kaslr_base + off_init_user_ns — prova que o layout .data/.bss do kernel em execução corresponde à tabela de offsets antes de qualquer escrita cega |
| Vazamento de mm_struct | KernelSnitch -- canal lateral de temporização por colisão de hash de futex |
| Heap spray | Coreografia de descarte SLUB (memfd-close, overflow de CPU-parcial) + recuperação de página de ordem 2 via io_uring_setup(256) |
| Sobreposição de pilha | AF_UNIX SOCK_SEQPACKET sendmsg -- move_addr_to_kernel copia sockaddr de 128 bytes para a pilha do kernel, sobrepondo os campos task/lock/prio do waiter pendente |
| Disparo da caminhada | sched_setattr com escada monotônica de nice (7 -> 14 -> 19) dispara a caminhada da cadeia PI, uma por rodada de sobreposição |
| Primitiva de escrita | rb_erase Caso 1: `{pc=(TARGET-8) |
| Desligar SELinux (caminhada 0) | Zero de 8 bytes em selinux_state limpa enforcing, checkreqprot, initialized e policycap[0..4] — avc_denied() nunca nega (enforcing=0) e security_compute_av() encurta para permitir-tudo (!initialized), então o kernel-SID pós-troca (u:r:kernel) deixa de importar |
| Troca de credenciais (caminhadas 1+2) | task->cred = fake_cred e task->real_cred = fake_cred (uid=0, caps FULL, user_namespace falso autocontido na página de spray; ambas as escritas necessárias — commit_creds() no exec dispara BUG_ON a menos que cred == real_cred) |
| Bateria de root | sondas somente de syscall bruta (uid/SELinux//proc/1//dev/kmsg/wifi/pacotes//data/data/kallsyms) em /data/local/tmp/.ghostlock_out |
| Shell root | execve("/system/bin/sh") — commit_creds no caminho de exec copia fake_cred para uma credencial de slab limpa; condicionado a todas as exclusões planejadas terem sido efetivadas |
rb_right = 0 realiza um único armazenamento limpo de zero de 8 bytes em um endereço arbitrário do kernel (sem armazenamento lateral, sem desreferências selvagens); zerar o primeiro qword de selinux_state resulta em dupla permissividade (enforcing=0 + !initialized → permitir tudo), o que desbloqueia toda a E/S de arquivos pós-root apesar do SID do kernel&init_user_ns do caminho ativo security_capable() e aborta para o fluxo somente cred, a menos que corresponda a kaslr_base + off_init_user_nsucounts = NULL -- cap_capable corresponde na primeira iteração e inc_rlimit_ucounts termina após um loop, eliminando a necessidade de vazar &init_user_nsPERF_SAMPLE_TID garantem que apenas os instantâneos de registradores da thread chamadora sejam contados, impedindo que serviços de sistema ativos dominem a votação de modo5.15.170-android14-11-gf4a1f03072af (aarch64, PGO+BOLT+LTO, clang 17.0.2)CONFIG_FUTEX_PI=y, CONFIG_IO_URING=y, perf_event_paranoid=-1, SELinux enforcing, panic_on_oops=1, sem namespaces de usuárioexport ANDROID_NDK_HOME=/path/to/android-ndk
make -j$(nproc)
Requer o Android NDK (testado com r27). Produz um binário aarch64 com ligação estática.
adb push ghostlock /data/local/tmp/
adb shell "cd /data/local/tmp && ./ghostlock --cred"
O exploit leva ~25 segundos (vazamentos de KASLR/task/layout + heap spray + bruteforce do KernelSnitch + três rodadas de overlay de 3 segundos). Em caso de sucesso, ele grava a bateria de root em /data/local/tmp/.ghostlock_out, o marcador em /data/local/tmp/.ghostlock_root e executa /system/bin/sh com uid=0 sob um kernel permissivo.
Ajustes de ambiente:
GHOST_SELINUX=0 — ignora a escrita no SELinux, executa a rota comprovada apenas de credenciais (modo 6)GHOST_SELINUX_FORCE=1 — arma a escrita no SELinux mesmo se a validação de layout de símbolos do dispositivo falharGHOST_EXEC=0 — grava a bateria e sai com exit(99) em vez de executar um shellCRED_ATTEMPTS=n — tentativas de full-spray quando uma execução não consegue o reclaim (padrão 3)Este exploit foi portado e desenvolvido por Claude Opus 4.6 (Anthropic) com GLM-5.3 (Z.ai) como consultor de exploração de kernel.