
CVE-2026-43499 exploit root GhostLock per Chromecast con Google TV (sabrina)
Exploit root per Chromecast con Google TV (sabrina) tramite CVE-2026-43499 -- una use-after-free nel sottosistema futex PI (priority inheritance) del kernel Linux.
Ottiene root su un dispositivo con bootloader bloccato che esegue Android 14 con kernel 5.15.170 (PGO+BOLT+LTO, clang 17).
GhostLock sfrutta un bug in remove_waiter() chiamato dal percorso di rollback -EDEADLK in rt_mutex_start_proxy_lock(). La funzione azzera current->pi_blocked_on (quello del requeuer, già NULL) invece di quello del task waiter. Il pi_blocked_on del waiter non viene mai azzerato, lasciando un puntatore pendente a un rt_mutex_waiter liberato sullo stack del kernel.
Una successiva sched_setattr attiva rt_mutex_adjust_pi -> rt_mutex_adjust_prio_chain, che segue il puntatore pendente e percorre una catena PI su dati controllati dall'attaccante in una pagina heap riallocata -- fornendo una primitiva di scrittura arbitraria tramite rb_erase.
| Fase | Tecnica |
|---|---|
| Leak KASLR | perf_event_open con PERF_SAMPLE_IP (vincolato al TID) — l'IP minimo del kernel è in .entry.text (+0x10000), _text è allineato a 2MB e lo slide KASLR è un multiplo di 2MB, quindi min_ip & ~0x1fffff recupera esattamente il _text a runtime |
| Leak task struct | perf_event_open con PERF_SAMPLE_REGS_INTR (vincolato al TID, modalità degli indirizzi della mappa lineare) |
| Validazione della symbol table | I campioni perf di &init_user_ns dagli argomenti di registro di security_capable() durante una raffica di setpriority(-20) vengono confrontati con kaslr_base + off_init_user_ns — dimostra che il layout .data/.bss del kernel in esecuzione corrisponde alla tabella degli offset prima di qualsiasi scrittura cieca |
| Leak mm_struct | KernelSnitch -- side-channel temporale su collisione dell'hash futex |
| Heap spray | Coreografia di scarto SLUB (memfd-close, overflow CPU-partial) + recupero di pagine di ordine 2 tramite io_uring_setup(256) |
| Sovrapposizione dello stack | AF_UNIX SOCK_SEQPACKET sendmsg -- move_addr_to_kernel copia 128 byte di sockaddr sullo stack del kernel, sovrapponendosi ai campi task/lock/prio del waiter pendente |
| Trigger del walk | sched_setattr con scala nice monotona (7 -> 14 -> 19) attiva il walk della catena PI, uno per ogni round di sovrapposizione |
| Primitiva di scrittura | rb_erase Caso 1: `{pc=(TARGET-8) |
| Disattivazione SELinux (walk 0) | Zero a 8 byte su selinux_state azzera enforcing, checkreqprot, initialized e policycap[0..4] — avc_denied() non nega mai (enforcing=0) e security_compute_av() va in cortocircuito verso allow-all (!initialized), quindi il kernel-SID post-swap (u:r:kernel) smette di avere importanza |
| Scambio credenziali (walk 1+2) | task->cred = fake_cred e task->real_cred = fake_cred (uid=0, caps FULL, user_namespace fittizio autocontenuto sulla pagina dello spray; entrambe le scritture necessarie — commit_creds() all'exec va in BUG_ON a meno che cred == real_cred) |
| Batteria di test root | sonde solo raw-syscall (uid/SELinux//proc/1//dev/kmsg/wifi/pacchetti//data/data/kallsyms) in /data/local/tmp/.ghostlock_out |
| Shell root | execve("/system/bin/sh") — commit_creds nel percorso di exec copia fake_cred in una credenziale slab pulita; vincolata al fatto che tutte le cancellazioni pianificate siano andate a segno |
rb_right = 0 esegue un singolo store pulito di 8 byte a zero su un indirizzo kernel arbitrario (nessuno store collaterale, nessuna dereferenziazione selvaggia); azzerare il primo qword di selinux_state produce il doppio permissive (enforcing=0 + !initialized → allow-all), che sblocca tutto l'I/O su file post-root nonostante il SID del kernel&init_user_ns dal percorso live di security_capable() e interrompe verso il flusso solo-cred a meno che non corrisponda a kaslr_base + off_init_user_nsucounts = NULL -- cap_capable trova corrispondenza alla prima iterazione e inc_rlimit_ucounts termina dopo un solo ciclo, eliminando la necessità di fare leak di &init_user_nsPERF_SAMPLE_TID garantiscono che vengano conteggiati solo gli snapshot dei registri del thread chiamante, impedendo ai servizi di sistema più attivi di dominare il voto della modalità5.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, nessun user namespaceexport ANDROID_NDK_HOME=/path/to/android-ndk
make -j$(nproc)
Richiede l'Android NDK (testato con r27). Produce un binario aarch64 collegato staticamente.
adb push ghostlock /data/local/tmp/
adb shell "cd /data/local/tmp && ./ghostlock --cred"
L'exploit richiede circa 25 secondi (leak di KASLR/task/layout + heap spray + bruteforce di KernelSnitch + tre round di overlay da 3 secondi). In caso di successo scrive la batteria root in /data/local/tmp/.ghostlock_out, il marker in /data/local/tmp/.ghostlock_root, ed esegue /system/bin/sh con uid=0 sotto un kernel permissivo.
Parametri di ambiente:
GHOST_SELINUX=0 — salta la scrittura SELinux, esegue il percorso cred-only collaudato (modalità 6)GHOST_SELINUX_FORCE=1 — attiva la scrittura SELinux anche se la validazione del layout dei simboli del dispositivo fallisceGHOST_EXEC=0 — scrive la batteria ed esce con exit(99) invece di eseguire una shellCRED_ATTEMPTS=n — tentativi di full-spray quando un'esecuzione non riesce a recuperare la memoria (default 3)Questo exploit è stato portato e sviluppato da Claude Opus 4.6 (Anthropic) con GLM-5.3 (Z.ai) come consulente per lo sfruttamento del kernel.