CVE-2026-98256
signal: exec()-Race verhindern
- Veröffentlicht
- 06.10.2026
- Aktualisiert
- 19.10.2026
- CNA zuweisen
- Linux
- Beweise beobachtet
- 04.11.2026
Primäres CVSS
nvd · CVSS 3.1
CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:HNiedrig · nächste 30 Tage
- Perzentil
- 3,7 %
- Modelldatum
- 04.11.2026
EPSS ist eine statistische Schätzung, keine Gewissheit oder ein Maß für die Auswirkung. Kombinieren Sie es mit CVSS, KEV-Status, Belichtung und Ihrer Umgebung.
Zusammenfassung
Im Linux-Kernel wurde die folgende Schwachstelle behoben: signal: Prevent exec() race Hyunwoo hat den folgenden KASAN-UAF-Splat debuggt: BUG: KASAN: slab-use-after-free in __send_signal_locked+0xb27/0xba0 Write of size 8 at addr ffff888007ed80c8 by task poc/79 ... Call Trace: __send_signal_locked+0xb27/0xba0 do_send_sig_info+0xa7/0x160 do_send_specific+0x76/0xa0 __x64_sys_tgkill+0x193/0x270 ... Allocated by task 80: do_timer_create+0x1a4/0x1030 __x64_sys_timer_create+0x145/0x190 ... Freed by task 12: kmem_cache_free_bulk+0x1f8/0x4a0 kvfree_rcu_bulk+0x14f/0x1c0 kfree_rcu_work+0x128/0x1a0 ... Last potentially related work creation: kvfree_call_rcu+0x39/0x390 __flush_itimer_signals+0x211/0x320 flush_itimer_signals+0x47/0x90 begin_new_exec+0xa6b/0x28c0 Es stellte sich heraus, dass dies bei einem exec() eines Nicht-Leaders auftritt, wie Hyunwoo erklärte: de_thread() ruft exchange_tids() vor release_task(leader) auf, sodass die struct pid, die von einem SIGEV_THREAD_ID-Timer gehalten wird, der gegen die tid des Leaders erstellt wurde, nun auf den Thread zeigt, der execve() aufgerufen hat. pid_task() gibt diesen Thread zurück und lock_task_sighand() darauf ist erfolgreich. Wenn das Timer-Signal blockiert ist, bleibt seine sigqueue in task::pending des Leaders eingereiht. Der nächste Ablauf dieses Timers kann dann ausgeführt werden, während release_task() die Warteschlange leert. posixtimer_send_sigqueue() prüft mit einem einfachen list_empty(), ob die sigqueue bereits eingereiht ist, was nur list_head::next liest. list_del_init() ist nicht atomar und INIT_LIST_HEAD() speichert list_head::next vor list_head::prev, sodass die Prüfung dazwischen erfolgreich sein kann. list_add_tail() reiht den Eintrag in task::pending des lebenden Threads ein, und der list_head::prev-Speichervorgang aus dem Flush überschreibt dann die list_head::prev-Verknüpfung, die list_add_tail() gerade gesetzt hat. __flush_itimer_signals() macht das auch nicht rückgängig. Da list_head::prev auf den Eintrag selbst zeigt, speichert sein list_del_init() nur dieselben Werte erneut, sodass der Eintrag nicht aus der Liste entfernt wird. Er ist auch nach dem Fallenlassen der letzten Referenz und dem Freigeben des Timers durch RCU noch vorhanden, und das list_add_tail() eines späteren tgkill() folgt dieser list_head::prev in den freigegebenen Timer. Dieses Problem trat mit dem kürzlichen Commit auf, der den sigqueue-Flush aus dem Bereich, in dem der sighand-Lock gehalten wird, heraus verschoben hat. Hyonwoo schlug vor, dies durch die Verwendung von list_del_init_careful() zu beheben, aber das übertüncht das Problem nur. Nach einigen Diskussionen und verschiedenen Lösungsversuchen wies Eric darauf hin, dass es keinen Grund gibt, task::pending spät in release_task() zu leeren, und dies bereits in exit_signals() erfolgen sollte. Da nichts Signale sammeln und zustellen kann, die in der pending-Warteschlange einer sterbenden Task eingereiht sind, gibt es keinen Grund, dies weiter zu verzögern. Es muss jedoch sichergestellt werden, dass danach keine Signale mehr darin eingereiht werden können. exit_signals() setzt PF_EXITING in task::flags, was als Indikator dafür verwendet werden kann. Behebung durch: - Verhindern des Einreihens von Signalen für task-private Signale (PIDTYPE_PID), wenn bei der Task PF_EXITING gesetzt ist, in __send_signal_locked() und in posixtimer_send_sigqueue(). - Schützen des ungesperrten Setzens von PF_EXITING in exit_signals() für den Fall einer leeren Task-Gruppe und den Fall des Gruppen-Exits mit dem sighand-Lock - Leeren der task::pending-Signale genau dort. Optimierung durch Verschieben der gesamten pending-Liste auf einen On-Stack-Listenkopf unter dem sighand-Lock und Freigeben der Signale ohne gehaltenen Lock. Es gab einige Diskussionen über den lockfreien Flush und den Nicht-Leader-exec-Fall auf schwach geordneten Systemen. Das Problem ist, dass ein Dritter, der versucht, ein POSIX-Timer-Signal zu senden, sich auf die PID-Suche verlässt, um die Ziel-Task zu finden, und diese Suche möglicherweise zum neuen Leader führt, wenn das Signal ursprünglich an den alten Leader gerichtet war. Falls das Signal beim alten Leader eingereiht wurde, warf der lockfreie Flush Bedenken hinsichtlich der folgenden Situation auf: old_leader new_leader third party A: flush_list() // list_del_in ---gekürzt---
Verantwortungsvoller Umgang
Verwenden Sie Schwachstelleninformationen nur auf Systemen, die Sie besitzen oder zu deren Testen Sie berechtigt sind. Kitploit verlinkt auf öffentliche Forschungsmetadaten und speichert keinen Exploit-Code oder bösartige Payloads.