CVE-2026-64560
posix-cpu-timers:防止由非领导者 exec() 竞争导致的 UAF
- 已发布
- 2026年7月29日
- 已更新
- 2026年9月8日
- 分配 CNA
- Linux
- 观察到的证据
- 2026年8月10日
初级CVSS
nvd · CVSS 3.1
CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H低 · 未来 30 天
- 百分位
- 35.5%
- 型号日期
- 2026年9月21日
EPSS 是统计估计,而不是确定性或影响衡量标准。将其与 CVSS、KEV 状态、暴露程度和您的环境相结合。
总结
在 Linux 内核中,已解决以下漏洞:posix-cpu-timers:防止由非领导者 exec() 竞争导致的 UAF Wongi 和 Jungwoo 解码并报告了一个与非领导者 exec() 相关的竞争,该竞争可能导致 UAF: ``` sys_timer_delete() exec() de_thread() switch_leader(); release_task(old_leader) __exit_signal(old_leader) sighand = lock(old_leader, sighand); posix_cpu_timers*_exit(); unhash_task(old_leader); old_leader->sighand = NULL; unlock(sighand); posix_cpu_timer_del() // Observes old leader p = pid_task(pid, pid_type); sighand = lock_task_sighand(p) sh = lock(p, sighand) (p->sighand == NULL) unlock(sh) return NULL; // Returns without action if(!sighand) return 0; free_posix_timer(); ``` 这“无害”,除非被删除的定时器已武装并排入 p->signal 队列,因为在 exec() 时,针对 TGID 的定时器会被继承。由于 sys_timer_delete() 释放了底层的 posix 定时器对象,run_posix_cpu_timers() 或任何其他定时器上的 timerqueue 相关添加/删除操作将访问已释放对象的 timerqueue 节点,从而导致 UAF。 posix_cpu_timer_set() 也存在类似问题。对于常规 posix 定时器,它只是暂时向用户空间返回 -ESRCH,但对于 do_cpu_nanosleep() 中的用例,这是相同的 UAF,只是 k_itimer 是在栈上分配的。此外,posix_cpu_timer_rearm() 无法重新武装定时器,这意味着它停止到期。 在讨论解决方案时,Frederic 指出了另一个问题: ``` posix_cpu_timer_del(tmr) __exit_signal(p) posix_cpu_timers*_exit(p); unhash_task(p); p->sighand = NULL; sh = lock_task_sighand(p) sighand = p->sighand; if (!sighand) return NULL; lock(sighand); if (!sh) WARN_ON_ONCE(timer_queued(tmr)); ``` 在弱有序架构上,当 p->sighand 被观察为 NULL 时,无法保证 posix_cpu_timer_del() 会观察到 posix_cpu_timers*_exit() 中的存储,这意味着 WARN() 可能是误报。 通过以下方式解决这些问题: 1) 将 __exit_signal() 中的存储更改为 smp_store_release()。 2) 在 lock_task_sighand() 的 !sighand 路径中添加 smp_acquire__after_ctrl_dep()。 3) 创建一个用于查找任务并锁定 sighand 的辅助函数,该函数在 sighand == NULL 时不返回。相反,它会重试任务查找,并且仅当该查找失败时才放弃。 4) 在三个受影响的函数中使用该辅助函数。 #1/#2 确保观察到 sighand == NULL 的读取方也能观察到所有先前的存储,即 posix_cpu_timers*_exit() 中的存储以及 unhash_task() 中的存储。#3 确保上述非领导者 exec() 情况得到妥善处理。当任务查找返回旧领导者,但 sighand == NULL 时,它会重试。在非领导者 exec() 情况下,由于 #1/#2,后续的任务查找将观察到新领导者。在正常的 exit() 场景中,后续查找会失败。当任务查找失败时,该函数还会检查定时器是否仍处于排队状态,如果是,则发出警告。不幸的是,对此无能为力,但由于任务已不再可见,因此不应再访问该定时器。此检查还需要内存排序,而首次查找失败时并不提供该排序。为实现这一点,检查之前有一个 smp_rmb(),它与 __exit_signal() 中 write_seqlock() 的 smp_wmb() 配对。这确保 posix_cpu_timers*_exit() 中的存储可见。 非领导者 exec() 问题的历史可以追溯到 posix CPU 定时器的早期,当时定时器中存储了指向组领导任务的指针。当非领导者 exec() 切换领导者时,这显然会失败。commit e0a70217107e(“posix-cpu-timers: workaround to suppress the problems with mt exec”)在 2010 年添加了一个临时解决方法,该解决方法存续了——已截断——
负责任的使用
仅在您拥有或有权测试的系统上使用漏洞信息。 Kitploit 链接到公共研究元数据,并且不存储漏洞代码或恶意负载。