
Linux-Kernel-UAF-Analyse für CVE-2026-64560 mit Race-auslösendem PoC, Patch-Review, Matrix der betroffenen LTS-/Android-Versionen und Selbstcheck für gepatchte Geräte.
Reproducer / PoC (Trigger-Verifikation): Linux & Android (NDK) Dieses Repository dient ausschließlich der Verifikation des Patch-Status auf eigenen Testgeräten sowie zu Studienzwecken; es enthält keinerlei Privilege-Escalation-/Exploit-Primitive.
| Feld | Inhalt |
|---|---|
| CVE ID | CVE-2026-64560 |
| Titel | posix-cpu-timers: Prevent UAF caused by non-leader exec() race |
| Typ | Use-After-Free (CWE-416), Race Condition |
| CNA | kernel.org (Linux CNA) |
| CVSS v3.1 | 7.8 High — CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H |
| CVSS v4.0 (SUSE) | 8.5 High — CVSS:4.0/AV:L/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N |
| EPSS | ~0.12 % (2. Perzentil, Stand 2026-08) |
| CISA KEV | Nicht gelistet |
| Veröffentlichungsdatum | 2026-07-29 |
| Fix-Commit (Mainline) | 920f893f735e92ba3a1cd9256899a186b161928d |
| Problemverursachender Commit (Fixes:) | 55e8c8eb2c7b (v5.7, 2020) — „posix-cpu-timers: Store a reference to a pid not a task“ |
| Beheber | Thomas Gleixner <[email protected]> |
| Melder | Wongi Lee <[email protected]>, Jungwoo Lee <[email protected]> |
| Betroffene Dateien | kernel/exit.c, kernel/signal.c, kernel/time/posix-cpu-timers.c |
Die Schwachstelle wurde in v5.7 (2020-05) eingeführt; der Fix wurde in die jeweiligen Stable-Zweige zurückportiert:
| Zweig | Betroffen | Fix-Version (≥) | Stable-Fix-Commit |
|---|---|---|---|
| 5.10 LTS | 5.7 ~ 5.10.261 | 5.10.262 | 67aa823e3e8c |
| 5.15 LTS | ~ 5.15.212 | 5.15.213 | d8bcb28abad8 |
| 6.1 LTS | ~ 6.1.179 | 6.1.180 | cc35ddbc4973 |
| 6.6 LTS | ~ 6.6.146 | 6.6.147 | 12a891c773ae |
| 6.12 LTS | ~ 6.12.99 | 6.12.100 | e74443f5db00 |
| 6.18 | ~ 6.18.40 | 6.18.41 | 6a7ecc25abe6 |
| 7.1 | ~ 7.1.4 | 7.1.5 | ad1cafa1bdaa |
| Mainline | < 7.2-rc3 | 7.2-rc3 | 920f893f735e |
Android-GKI-Kernel basieren auf 5.10 / 5.15 / 6.1 / 6.6 / 6.12 LTS und sind sämtlich betroffen. Da der Mainline-Fix-Commit am 2026-07-29 veröffentlicht wurde, haben Android-Geräte mit SPL (Security Patch Level) bis einschließlich 2026-08-01 den Fix praktisch noch nicht übernommen. Auf dem Gerät lässt sich die Kernelversion und das SPL mit adb shell cat /proc/version und getprop ro.build.version.security_patch überprüfen.
POSIX-CPU-Timer (timer_create(CLOCK_PROCESS_CPUTIME_ID, ...) / timer_create(CLOCK_THREAD_CPUTIME_ID, ...)) werden im Kernel von kernel/time/posix-cpu-timers.c verwaltet. Jedes k_itimer merkt sich das Ziel-Task über it.cpu.pid; für Timer-Operationen wird lock_task_sighand(p, &flags) benötigt, um die sighand->siglock des Tasks zu sperren und die Timerqueue zu schützen.
Der Commit 55e8c8eb2c7b aus dem Jahr 2020 ersetzte den im Timer gecachten Task-Zeiger durch eine PID-Referenz (um das durch den Workaround von 2010, e0a70217107e, verursachte Problem zu beheben). Vor jeder Operation wird eine Suche mit pid_task(pid, type) durchgeführt. Diese Änderung hinterließ das Race-Fenster dieser CVE.
Wenn execve() von einem Nicht-Leader-Thread ausgelöst wird, überträgt de_thread() → switch_leader() die TGID vom alten auf den neuen Leader. Der alte Leader durchläuft release_task() → __exit_signal(), wobei old_leader->sighand = NULL gesetzt und unhash_task(old_leader) ausgeführt wird.
Gleichzeitig läuft auf einer anderen CPU sys_timer_delete() → posix_cpu_timer_del():
sys_timer_delete() exec()
posix_cpu_timer_del()
// 观察到旧 leader
p = pid_task(pid, pid_type); de_thread()
switch_leader();
release_task(old_leader)
__exit_signal(old_leader)
sighand = lock(old_leader, sighand);
posix_cpu_timers*_exit();
sighand = lock_task_sighand(p) unhash_task(old_leader);
sh = lock(p, sighand) old_leader->sighand = NULL;
unlock(sighand);
(p->sighand == NULL)
unlock(sh)
return NULL;
// 直接返回,没有摘链!
if (!sighand)
return 0;
free_posix_timer(); // ← k_itimer 被释放
Das von posix_cpu_timer_del() ermittelte p ist der alte Leader; da p->sighand == NULL ist, nimmt die Funktion an, dass „das Task gerade beendet wird und der Exit-Pfad das Entfernen aus der Queue übernimmt“, und gibt ohne jede Aktion Erfolg zurück. Anschließend gibt free_posix_timer() das k_itimer frei.
Kernpunkt: Anders als exit() ändert exec() die TGID nicht; armed Timer auf Prozessebene (p->signal->cpu_timers) werden vererbt und bleiben eingereiht. Daher:
run_posix_cpu_timers() (durchläuft die Timerqueue im Tick) greift auf das timerqueue_node des freigegebenen Objekts zu → UAF-Lesen/-Schreiben;Gleichartige Probleme bestehen auch in:
posix_cpu_timer_set(): Normale Timer geben lediglich vorübergehend -ESRCH zurück; der kernelinterne do_cpu_nanosleep() verwendet jedoch ein auf dem Stack allokiertes k_itimer – dieselbe UAF.posix_cpu_timer_rearm(): Das Rearm schlägt still fehl, der Timer läuft nicht mehr ab (funktionaler Bug).Frederic Weisbecker weist darauf hin: tsk->sighand = NULL in __exit_signal() ist ein gewöhnlicher Store. Auf Architekturen mit schwacher Speicherordnung wie ARM64 ist nicht garantiert, dass posix_cpu_timer_del() beim Beobachten von sighand == NULL auch die vor posix_cpu_timers*_exit() durchgeführten Entfernungs-Schreibvorgänge sieht, wodurch WARN_ON_ONCE(timer_queued(tmr)) fälschlich ausgelöst werden kann.
__exit_signal() wird auf smp_store_release(&tsk->sighand, NULL) umgestellt;!sighand-Pfad von lock_task_sighand() erhält smp_acquire__after_ctrl_dep();timer_lock_sighand(): Task nachschlagen + sighand sperren; bei sighand == NULL wird nicht zurückgekehrt, sondern die Suche wiederholt – im Exec-Szenario findet man den neuen Leader, im Exit-Szenario gibt man erst auf, wenn die Suche fehlschlägt;_del / _set / _rearm) verwenden einheitlich diesen Helper.Das vollständige Diff siehe patches/920f893f735e.patch.
Unter poc/ wird ein Race-Trigger bereitgestellt: Zwei Threads durchlaufen jeweils eine intensive Schleife