CVE-2026-98256
signal: exec() 경쟁 조건 방지
- 게시됨
- 2026. 10. 6.
- 업데이트됨
- 2026. 10. 19.
- CNA 할당 중
- Linux
- 증거 관찰됨
- 2026. 11. 4.
기본 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일
- 백분위수
- 3.7%
- 모델 날짜
- 2026. 11. 4.
EPSS는 통계적 추정치이지 확실성이나 영향의 척도가 아닙니다. 이를 CVSS, KEV 상태, 노출 및 환경과 결합하세요.
요약
Linux 커널에서 다음과 같은 취약점이 해결되었습니다: signal: exec() 경쟁 조건 방지. Hyunwoo는 다음과 같은 KASAN UAF splat을 디버깅했습니다: 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 이 문제는 Hyunwoo가 설명한 대로 리더가 아닌 스레드의 exec()에서 발생하는 것으로 밝혀졌습니다: de_thread()는 release_task(leader) 전에 exchange_tids()를 호출하므로, 리더의 tid를 대상으로 생성된 SIGEV_THREAD_ID 타이머가 보유한 struct pid가 이제 execve()를 호출한 스레드를 가리키게 됩니다. pid_task()는 해당 스레드를 반환하고 그에 대한 lock_task_sighand()가 성공합니다. 타이머 시그널이 블록되어 있으면 해당 sigqueue는 리더의 task::pending에 계속 큐에 남아 있습니다. 그런 다음 해당 타이머의 다음 만료가 release_task()가 큐를 플러시하는 동안 실행될 수 있습니다. posixtimer_send_sigqueue()는 sigqueue가 이미 큐에 있는지 단순한 list_empty()로 확인하는데, 이는 list_head::next만 읽습니다. list_del_init()은 원자적이지 않고 INIT_LIST_HEAD()는 list_head::prev보다 list_head::next를 먼저 저장하므로, 그 사이에 확인이 통과될 수 있습니다. list_add_tail()은 해당 엔트리를 살아있는 스레드의 task::pending에 큐에 넣고, 플러시에서의 list_head::prev 저장이 list_add_tail()이 방금 설정한 list_head::prev 링크를 덮어씁니다. __flush_itimer_signals()도 이를 되돌리지 않습니다. list_head::prev가 엔트리 자신을 가리키게 되면, 해당 list_del_init()은 같은 값만 다시 저장하므로 엔트리는 리스트에서 제거되지 않습니다. 마지막 참조가 해제되고 타이머가 RCU에 의해 해제된 후에도 여전히 남아 있으며, 이후 tgkill()의 list_add_tail()이 해당 list_head::prev를 따라 해제된 타이머로 들어갑니다. 이 문제는 sigqueue 플러시를 sighand 락이 잡힌 영역 밖으로 옮긴 최근 커밋과 함께 표면화되었습니다. Hyonwoo는 list_del_init_careful()을 사용하여 이를 수정할 것을 제안했지만, 그것은 문제를 덮을 뿐입니다. 몇 가지 논의와 다양한 해결 시도 끝에 Eric은 release_task() 후반에 task::pending을 플러시할 이유가 없으며 exit_signals()에서 이미 수행되어야 한다고 지적했습니다. 죽어가는 태스크의 pending 큐에 큐에 넣어진 시그널을 수집하고 전달할 수 있는 것은 아무것도 없으므로, 이를 더 지연시킬 이유가 없습니다. 그러나 그 시점 이후로는 시그널이 큐에 들어갈 수 없도록 보장해야 합니다. exit_signals()는 task::flags에 PF_EXITING을 설정하며, 이는 이를 위한 지표로 사용될 수 있습니다. 다음과 같이 수정합니다: - __send_signal_locked() 및 posixtimer_send_sigqueue()에서 태스크에 PF_EXITING이 설정된 경우 태스크 전용 시그널(PIDTYPE_PID)에 대한 시그널 큐잉을 방지합니다. - 태스크 그룹이 비어 있는 경우와 그룹 종료 사례에 대해 exit_signals()에서 PF_EXITING의 락 없는 설정을 sighand 락으로 보호합니다. - 바로 그 지점에서 task::pending 시그널을 플러시합니다. sighand 락 하에서 전체 pending 리스트를 스택 위의 리스트 헤드로 옮기고 락을 잡지 않은 상태에서 시그널을 해제하여 이를 최적화합니다. 락 없는 플러시와 약한 순서 지정 시스템에서의 비리더 exec 사례에 관해 상당한 논의가 있었습니다. 문제는 posix 타이머 시그널을 보내려는 제3자가 PID 조회에 의존하여 대상 태스크를 찾는다는 점이며, 해당 조회는 시그널이 원래 이전 리더를 향했을 때 새로운 리더를 결과로 낼 수 있습니다. 시그널이 이전 리더에 큐에 넣어진 경우, 락 없는 플러시는 다음과 같은 상황에 대한 우려를 제기했습니다: old_leader new_leader third party A: flush_list() // list_del_in ---truncated---
책임 있는 사용
귀하가 소유하고 있거나 테스트할 권한이 있는 시스템에 대해서만 취약점 정보를 사용하십시오. Kitploit은 공개 연구 메타데이터에 연결되며 익스플로잇 코드나 악성 페이로드를 저장하지 않습니다.