
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:
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
timer_create(CLOCK_PROCESS_CPUTIME_ID) → arming (sehr kurze anfängliche Verfallszeit) → Busy-Wait bis zum Auslösen → timer_delete();fork() → im Kindprozess einen Nicht-Leader-Thread erstellen, der execve() aufruft (Non-Leader-Exec ist eine notwendige Bedingung dieser Schwachstelle); der Elternprozess ruft sofort waitpid() zur Wiederverwertung auf.Wenn timer_delete() genau mit de_thread()/__exit_signal() um die Wette konkurriert, bleibt in ungepatchten Kernen das bereits freigegebene k_itimer weiterhin im R-Baum von signal->cpu_timers hängen; danach greifen run_posix_cpu_timers() oder andere Timerqueue-Operationen auf den verwaisten Knoten zu. Mit einem KASAN-Kernel lassen sich zuverlässig Meldungen wie BUG: KASAN: use-after-free in run_posix_cpu_timers / timerqueue_del beobachten; ohne KASAN äußert sich das typischerweise als gelegentliche Kernel-Warnung oder Panic.
Hinweis zur Art des Inhalts: Dies ist ein reiner C-Race-Trigger; er enthält keinerlei Exploit-Primitive wie Heap-Spray, Objekt-Platzhalter oder RIP-Kontrolle. Um daraus einen Privilege-Escalation-Exploit zu machen, wäre erheblich zusätzliche Arbeit nötig (Heap-Feng-Shui, Platzhalterobjekte im Slab-Cache von
k_itimer, Umgehung von KASLR/CFI usw.) und es hängt stark vom jeweiligen Kernel-Build ab. Dieses Repository enthält diesen Teil bewusst nicht.
├── README.md ← 本文
├── patches/
│ └── 920f893f735e.patch ← mainline 修复补丁全文
└── poc/
├── cve_2026_64560_poc.c ← 触发器源码(Linux/Android 通用)
├── Makefile ← Linux / NDK 交叉编译
└── Android.mk ← NDK ndk-build(可选)
cd poc
make # 生成 cve_2026_64560_poc
sudo ./cve_2026_64560_poc -d 60
# 观察 dmesg: sudo dmesg -wH | grep -iE 'kasan|use-after|BUG|WARNING'
cd poc
export ANDROID_NDK_HOME=/path/to/ndk
make android # 生成 cve_2026_64560_poc_arm64(static, pie)
adb push cve_2026_64560_poc_arm64 /data/local/tmp/cvepoc
adb shell chmod 755 /data/local/tmp/cvepoc
adb shell /data/local/tmp/cvepoc -d 120
# 观察内核日志:
adb shell su 0 dmesg -w | grep -iE 'kasan|use-after|BUG|WARNING|timer'
# 无 root 时也可在触发崩溃后用 adb shell cat /sys/fs/pstore/console-ramoops* 查看
Das Gerät muss folgende Voraussetzungen erfüllen:
CLOCK_PROCESS_CPUTIME_ID-Timer zielen auf die TGID → hängen an signal->cpu_timers und werden nach dem Exec vererbt – das ist die Voraussetzung für die UAF (CLOCK_THREAD_CPUTIME_ID funktioniert nicht);switch_leader() bewirkt, dass der von pid_task(TGID) zurückgegebene alte Leader anschließend sighand = NULL hat – das ist die notwendige Bedingung für das Race;timer_create/arm/delete-Operationen parallel zu hochfrequentem fork/exec maximieren die Wahrscheinlichkeit, dass posix_cpu_timer_del() in das Fenster fällt; die Timer-Timeout-Verarbeitung (run_posix_cpu_timers) selbst berührt den verwaisten Knoten ebenfalls, ohne dass eine zusätzliche Auslösung nötig ist.# Android:
adb shell cat /proc/version # 内核版本是否 >= 上表修复版本
adb shell getprop ro.build.version.security_patch # SPL 是否 > 2026-08
# Linux:
uname -r
# 或直接检查源码是否包含 timer_lock_sighand:
grep -r timer_lock_sighand /usr/src/linux/kernel/time/posix-cpu-timers.c
Wenn der PoC mehrere Minuten ohne KASAN/Panic läuft und die Kernelversion ≥ der Fix-Version ist, gilt das Gerät als behoben (der PoC bietet außerdem einen --check-Modus für einen leichten Smoke-Test).
Dieses Repository dient ausschließlich der Sicherheitsforschung und Verteidigungsverifikation. Führen Sie es nur auf Geräten aus, die Ihnen gehören oder für die Sie eine schriftliche Genehmigung haben. Der PoC kann Kernel-Instabilität bis hin zur Panic auslösen; führen Sie ihn nicht auf Produktionsgeräten aus. Die Autoren übernehmen keine Verantwortung für Folgen jedweder missbräuchlichen Verwendung.
| 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 |