CVE-2026-64560
posix-cpu-timers: 非リーダーexec()レースによって引き起こされるUAFを防止
- 公開済み
- 2026/07/29
- 更新済み
- 2026/09/08
- CNA の割り当て
- Linux
- 観察された証拠
- 2026/08/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/09/21
EPSS は統計的な推定値であり、確実性や影響の尺度ではありません。 CVSS、KEV ステータス、暴露、環境と組み合わせます。
概要
Linuxカーネルにおいて、以下の脆弱性が解決されました: posix-cpu-timers: 非リーダーexec()競合によるUAFを防止 Wongi氏とJungwoo氏は、UAFを引き起こす可能性のある非リーダーexec()関連の競合を解析し、報告しました: ``` 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() // 古いリーダーを観測 p = pid_task(pid, pid_type); sighand = lock_task_sighand(p) sh = lock(p, sighand) (p->sighand == NULL) unlock(sh) return NULL; // アクションなしで返る 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()での使用ケースでは、k_itimerがスタック上に割り当てられているため、同じUAFが発生します。また、posix_cpu_timer_rearm()はタイマーの再アームに失敗し、タイマーが期限切れで停止することを意味します。 解決策を検討している際に、Frederic氏は別の問題を指摘しました: ``` posix_cpu_timer_del(tmr) sh = lock_task_sighand(p) sighand = p->sighand; if (!sighand) return NULL; lock(sighand); __exit_signal(p) posix_cpu_timers*_exit(p); unhash_task(p); p->sighand = NULL; 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) 影響を受ける3つの関数でそのヘルパーを使用する。 #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 は公開研究メタデータにリンクしており、エクスプロイト コードや悪意のあるペイロードは保存しません。