
Análise de UAF no kernel Linux para o CVE-2026-64560 com PoC de disparo por race condition, revisão de patch, matriz de versões LTS/Android afetadas e autoverificação para dispositivos corrigidos.
Reproducer / PoC (validação de gatilho) : Linux e Android (NDK) Este repositório destina-se apenas a verificar o estado do patch e estudo/pesquisa nos seus próprios dispositivos de teste, não contém nenhuma primitiva de escalonamento/exploração.
| Campo | Conteúdo |
|---|---|
| ID CVE | CVE-2026-64560 |
| Título | posix-cpu-timers: Prevent UAF caused by non-leader exec() race |
| Tipo | Use-After-Free (CWE-416), condição de corrida |
| 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º percentil, ponto de agosto de 2026) |
| CISA KEV | Não listada |
| Data de divulgação | 2026-07-29 |
| Commit de correção (mainline) | 920f893f735e92ba3a1cd9256899a186b161928d |
| Commit que introduziu o problema (Fixes:) | 55e8c8eb2c7b (v5.7, 2020) — "posix-cpu-timers: Store a reference to a pid not a task" |
| Correção por | Thomas Gleixner <[email protected]> |
| Relatado por | Wongi Lee <[email protected]>, Jungwoo Lee <[email protected]> |
| Arquivos afetados | kernel/exit.c, kernel/signal.c, kernel/time/posix-cpu-timers.c |
A vulnerabilidade foi introduzida na v5.7 (2020-05); a correção foi aplicada também (backport) em vários ramos estáveis:
Os kernels GKI do Android são baseados nos LTS 5.10 / 5.15 / 6.1 / 6.6 / 6.12, todos dentro do escopo afetado. Como o commit de correção na mainline foi publicado em 2026-07-29, os dispositivos Android com SPL (Security Patch Level) de 2026-08-01 ou anterior praticamente não incluem essa correção. No dispositivo, use adb shell cat /proc/version e getprop ro.build.version.security_patch para confirmar a versão do kernel e o SPL.
Os timers de CPU POSIX (timer_create(CLOCK_PROCESS_CPUTIME_ID, ...) / timer_create(CLOCK_THREAD_CPUTIME_ID, ...)) são gerenciados no kernel por kernel/time/posix-cpu-timers.c. Cada k_itimer lembra a tarefa alvo através de it.cpu.pid; ao operar no timer é necessário obter o sighand->siglock da tarefa via lock_task_sighand(p, &flags) para proteger a timerqueue.
O commit de 2020, 55e8c8eb2c7b, trocou o ponteiro de task armazenado em cache no timer por uma referência a pid (para corrigir o problema introduzido pelo workaround de 2010 e0a70217107e), fazendo uma busca pid_task(pid, type) antes de cada operação. Essa mudança deixou a janela de corrida deste CVE.
Quando execve() é iniciado por uma thread não-líder, de_thread() → switch_leader() transfere o TGID do líder antigo para o novo líder; o líder antigo passa por release_task() → __exit_signal(), que define old_leader->sighand = NULL e executa unhash_task(old_leader).
Enquanto isso, sys_timer_delete() → posix_cpu_timer_del() executando em outra CPU:
sys_timer_delete() exec()
posix_cpu_timer_del()
// observa o líder antigo
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;
// retorna direto, sem remover da fila!
if (!sighand)
return 0;
free_posix_timer(); // ← k_itimer é liberado
O p encontrado por posix_cpu_timer_del() é o líder antigo; nesse momento, p->sighand == NULL, e a função considera que "a tarefa está saindo, o caminho de exit cuidará da remoção da fila", portanto não faz nada e retorna sucesso. Em seguida, free_posix_timer() libera o k_itimer.
Ponto-chave: exec() é diferente de exit() — em exec(), o TGID não muda; os timers armados (armed) no nível do processo (p->signal->cpu_timers) são herdados e permanecem enfileirados. Assim:
run_posix_cpu_timers() (que percorre a timerqueue no tick) acessa o timerqueue_node de um objeto já liberado → UAF de leitura/escrita;Problemas semelhantes também existem em:
posix_cpu_timer_set(): um timer comum apenas retorna -ESRCH temporariamente; mas o do_cpu_nanosleep() interno do kernel usa um k_itimer alocado na pilha, sofrendo o mesmo UAF.posix_cpu_timer_rearm(): o rearm falha silenciosamente e o timer nunca mais expira (bug funcional).Frederic Weisbecker apontou: em __exit_signal(), tsk->sighand = NULL é um armazenamento comum; em arquiteturas de ordenação fraca, como ARM64, quando posix_cpu_timer_del() observa sighand == NULL, não é garantido que observe as escritas de remoção da fila anteriores a posix_cpu_timers*_exit(), podendo causar falsos positivos de WARN_ON_ONCE(timer_queued(tmr)).
__exit_signal(), alterado para smp_store_release(&tsk->sighand, NULL);!sighand de lock_task_sighand(), adicionado smp_acquire__after_ctrl_dep();timer_lock_sighand(): localiza a task + obtém o lock do sighand; se sighand == NULL, não retorna, mas tenta a busca novamente — no cenário de exec encontrará o novo líder; no cenário de exit, a busca falha e só então desiste;_del / _set / _rearm) passam a usar esse helper.O diff completo está em patches/920f893f735e.patch.
Em poc/ há um gatilho de corrida: duas threads executam loops intensos:
timer_create(CLOCK_PROCESS_CPUTIME_ID) → arm (com tempo inicial de expiração muito curto) → busy-wait até disparar → timer_delete();fork() → no processo filho, cria uma thread não-líder que chama execve() (exec de thread não-líder é condição necessária desta vulnerabilidade); o processo pai imediatamente faz waitpid() para reclamar.Quando timer_delete() coincide com de_thread()/__exit_signal() na corrida, em um kernel sem o patch o k_itimer já liberado ainda está pendurado na rbtree de signal->cpu_timers; depois, run_posix_cpu_timers() ou outras operações de timerqueue acessarão o nó pendurado. Com um kernel KASAN, é possível observar de forma estável relatos como BUG: KASAN: use-after-free in run_posix_cpu_timers / timerqueue_del; sem KASAN, normalmente aparecem avisos esporádicos do kernel ou panic.
Natureza: este é um gatilho de corrida puramente em C, sem heap spray, ocupação de objeto, controle de RIP ou qualquer primitiva de exploração. Transformá-lo em um exploit de escalonamento exigiria muito trabalho adicional (heap feng shui, objetos de ocupação no slab cache do
k_itimer, contornar KASLR/CFI etc.) e é fortemente dependente da construção específica do kernel. Este repositório deliberadamente não inclui essa parte.
├── README.md ← este documento
├── patches/
│ └── 920f893f735e.patch ← patch completo da correção na mainline
└── poc/
├── cve_2026_64560_poc.c ← código-fonte do gatilho (comum a Linux/Android)
├── Makefile ← compilação cruzada Linux / NDK
└── Android.mk ← NDK ndk-build (opcional)
cd poc
make # gera cve_2026_64560_poc
sudo ./cve_2026_64560_poc -d 60
# observe o dmesg: sudo dmesg -wH | grep -iE 'kasan|use-after|BUG|WARNING'
cd poc
export ANDROID_NDK_HOME=/path/to/ndk
make android # gera 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
# Observe o log do kernel:
adb shell su 0 dmesg -w | grep -iE 'kasan|use-after|BUG|WARNING|timer'
# Sem root, também é possível ver após o crash com: adb shell cat /sys/fs/pstore/console-ramoops*
O dispositivo precisa atender a:
CLOCK_PROCESS_CPUTIME_ID tem como alvo o TGID → fica em signal->cpu_timers e é herdado após exec — esse é o pré-requisito do UAF (CLOCK_THREAD_CPUTIME_ID não funciona);switch_leader() faz com que o líder antigo retornado por pid_task(TGID) fique imediatamente com sighand = NULL — essa é a condição necessária para a corrida;timer_create/arm/delete em alta frequência + fork/exec em alta frequência em paralelo maximizam a probabilidade de posix_cpu_timer_del() cair dentro da janela; o próprio tratamento de expiração do timer (run_posix_cpu_timers) também toca o nó pendurado, sem necessidade de gatilho adicional.# Android:
adb shell cat /proc/version # a versão do kernel é >= à versão corrigida na tabela acima?
adb shell getprop ro.build.version.security_patch # o SPL é > 2026-08?
# Linux:
uname -r
# ou verifique diretamente se o código-fonte contém timer_lock_sighand:
grep -r timer_lock_sighand /usr/src/linux/kernel/time/posix-cpu-timers.c
Se o PoC rodar por alguns minutos sem nenhum KASAN/panic e o kernel for ≥ à versão corrigida, considere corrigido (o PoC também possui um modo --check para uma validação leve de fumaça).
Este repositório destina-se exclusivamente a pesquisa de segurança e validação defensiva. Execute apenas em dispositivos que você possua ou para os quais tenha autorização por escrito. O PoC pode induzir instabilidade no kernel e até panic; não execute em dispositivos de produção. Os autores não se responsabilizam por consequências de qualquer uso indevido.
| Ramo | Afetadas | Versão corrigida (≥) | Commit de correção no stable |
|---|
| 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 |