
CVE-2026-43499 GhostLock Root-Exploit für Chromecast mit Google TV (sabrina)
Root-Exploit für Chromecast mit Google TV (sabrina) über CVE-2026-43499 -- ein Use-after-free im Futex-PI-Subsystem (Priority Inheritance) des Linux-Kernels.
Erlangt Root auf einem Gerät mit gesperrtem Bootloader, das Android 14 mit Kernel 5.15.170 ausführt (PGO+BOLT+LTO, clang 17).
GhostLock nutzt einen Fehler in remove_waiter(), der aus dem -EDEADLK-Rollback-Pfad in rt_mutex_start_proxy_lock() aufgerufen wird. Die Funktion löscht current->pi_blocked_on (das des RequEUERers, bereits NULL) statt das des Waiter-Tasks. Das pi_blocked_on des Waiters wird nie gelöscht, wodurch ein Dangling Pointer auf einen freigegebenen rt_mutex_waiter auf dem Kernel-Stack zurückbleibt.
Ein anschließendes sched_setattr löst rt_mutex_adjust_pi -> rt_mutex_adjust_prio_chain aus, was dem Dangling Pointer folgt und eine PI-Kette über angreiferkontrollierte Daten auf einer wiederbelegten Heap-Seite durchläuft -- was eine beliebige Schreibprimitive über rb_erase ermöglicht.
| Phase | Technik |
|---|---|
| KASLR-Leak | perf_event_open mit PERF_SAMPLE_IP (TID-gesteuert) — die minimale Kernel-IP liegt in .entry.text (+0x10000), _text ist 2MB-aligned und der KASLR-Slide ist ein 2MB-Vielfaches, sodass min_ip & ~0x1fffff das Laufzeit-_text exakt wiederherstellt |
| Task-Struct-Leak | perf_event_open mit PERF_SAMPLE_REGS_INTR (TID-gesteuert, Modus der Linear-Map-Adressen) |
| Symboltabellen-Validierung | Perf-Samples von &init_user_ns aus den Registerargumenten von security_capable() während eines setpriority(-20)-Sturms und Abgleich mit kaslr_base + off_init_user_ns — beweist, dass das .data/.bss-Layout des laufenden Kernels mit der Offset-Tabelle übereinstimmt, bevor ein blinder Schreibvorgang erfolgt |
| mm_struct-Leak | KernelSnitch -- Futex-Hash-Kollisions-Timing-Seitenkanal |
| Heap-Spray | SLUB-Discard-Choreografie (memfd-close, CPU-partial overflow) + io_uring_setup(256) Order-2-Seitenrückgewinnung |
| Stack-Overlay | AF_UNIX SOCK_SEQPACKET sendmsg -- move_addr_to_kernel kopiert 128-Byte-sockaddr auf den Kernel-Stack und überlagert die task/lock/prio-Felder des Dangling Waiters |
| Walk-Trigger | sched_setattr mit monotoner Nice-Leiter (7 -> 14 -> 19) löst den PI-Ketten-Walk aus, einer pro Overlay-Runde |
| Schreibprimitive | rb_erase Fall 1: `{pc=(TARGET-8) |
| SELinux aus (Walk 0) | 8-Byte-Null bei selinux_state löscht enforcing, checkreqprot, initialized und policycap[0..4] — avc_denied() verweigert nie (enforcing=0) und security_compute_av() schaltet auf Allow-All kurz (!initialized), sodass die Kernel-SID nach dem Swap (u:r:kernel) keine Rolle mehr spielt |
| Cred-Swap (Walks 1+2) | task->cred = fake_cred und task->real_cred = fake_cred (uid=0, Caps FULL, eigenständiger Fake-user_namespace auf der Spray-Seite; beide Schreibvorgänge erforderlich — commit_creds() beim exec BUG_ONs, es sei denn cred == real_cred) |
| Root-Batterie | Nur-Raw-Syscall-Probes (uid/SELinux//proc/1//dev/kmsg/wifi/packages//data/data/kallsyms) nach /data/local/tmp/.ghostlock_out |
| Root-Shell | execve("/system/bin/sh") — commit_creds im exec-Pfad kopiert fake_cred in ein sauberes Slab-Credential; gesteuert durch alle geplanten Erases, die gelandet sein müssen |
rb_right = 0 führt einen einzelnen sauberen 8-Byte-Null-Store an einer beliebigen Kernel-Adresse aus (kein Side-Store, keine Wild-Dereferenzierungen); das Nullen des ersten Qwords von selinux_state ergibt doppeltes Permissive (enforcing=0 + !initialized → allow-all), was alle Datei-I/O nach dem Root trotz der Kernel-SID freischaltet&init_user_ns per Perf aus dem Live-security_capable()-Pfad und bricht auf den Cred-only-Flow ab, sofern er nicht mit kaslr_base + off_init_user_ns übereinstimmtucounts = NULL -- cap_capable matcht beim ersten Durchlauf und inc_rlimit_ucounts terminiert nach einer Schleife, wodurch das Leaken von &init_user_ns entfälltPERF_SAMPLE_TID-Filter stellen sicher, dass nur die Register-Snapshots des aufrufenden Threads gezählt werden, wodurch verhindert wird, dass stark frequentierte Systemdienste die Modus-Abstimmung dominieren5.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, keine User-Namespacesexport ANDROID_NDK_HOME=/path/to/android-ndk
make -j$(nproc)
Erfordert das Android NDK (getestet mit r27). Erzeugt eine statisch gelinkte aarch64-Binärdatei.
adb push ghostlock /data/local/tmp/
adb shell "cd /data/local/tmp && ./ghostlock --cred"
Der Exploit benötigt ca. 25 Sekunden (KASLR-/Task-/Layout-Leaks + Heap-Spray + KernelSnitch-Bruteforce + drei 3-sekündige Overlay-Runden). Bei Erfolg schreibt er die Root-Batterie nach /data/local/tmp/.ghostlock_out, den Marker nach /data/local/tmp/.ghostlock_root und führt /system/bin/sh mit uid=0 unter einem permissiven Kernel aus.
Umgebungsschalter:
GHOST_SELINUX=0 — überspringt den SELinux-Schreibvorgang, führt die bewährte Cred-only-Route aus (Modus 6)GHOST_SELINUX_FORCE=1 — aktiviert den SELinux-Schreibvorgang auch dann, wenn die Validierung des Symbol-Layouts des Geräts fehlschlägtGHOST_EXEC=0 — schreibt die Batterie und beendet sich mit exit(99), anstatt eine Shell auszuführenCRED_ATTEMPTS=n — vollständige Spray-Wiederholungen, wenn ein Lauf den Reclaim verfehlt (Standard 3)Dieser Exploit wurde portiert und entwickelt von Claude Opus 4.6 (Anthropic) mit GLM-5.3 (Z.ai) als Kernel-Exploitation-Berater.
kernel/futex/, kernel/locking/rtmutex.c, lib/rbtree.c