CVE-2026-98644 in Linux
요약
\~에 의해 VulDB • 2026. 10. 18.
리눅스 커널에서 다음 취약점이 해결되었습니다:
bpf: __htab_map_lookup_and_delete_batch()에서의 soft lockup 방지
__htab_map_lookup_and_delete_batch()에는 rescheduling point가 없습니다. 배치 카운트는 방문된 버킷의 수가 아니라 복사되는 엔트리의 수를 제한하므로, 하나의 BPF_MAP_LOOKUP_BATCH 호출은 맵 전체를 순회할 수 있습니다. 빈 버킷에 대한 고속 경로(fast path)는 더 나쁕니다: 연속하는 빈 버킷이 있는 경우 단일 rcu_read_lock() / bpf_disable_instrumentation() 섹션 내부에서 계속 유지됩니다.
이는 작은 맵에서는 문제가 되지 않지만, 규모가 커지면 치명적입니다. 144-CPU arm64 호스트에서 CONFIG_PREEMPT_NONE 옵션의 커널을 실행 중일 때, 16,777,216개의 버킷을 가진 LRU 해시 맵에 대해 주기적으로 BPF_MAP_LOOKUP_BATCH 호출을 수행하면 CPU가 배치 작업(batch op) 내부에 77초 이상 고정되어 soft lockup watchdog를 트리거했습니다.
커밋 75134f16e7dd("bpf: Add schedule points in batch ops")는 제너릭(batch) ops에서 동일한 문제를 수정했지만, 모든 htab 기반 해시 맵 변형체가 lookup[_and_delete] 배치 ops에 사용하는 이 htab 네이티브 경로에서는 수정하지 않았습니다.
여기서 해당 수정을 완료합니다. 64개의 연속하는 빈 버킷 이후 critical section을 종료하고 cond_resched_tasks_rcu_qs()를 호출한 후 저장된 bucket cursor에서 재개합니다. 이때 잠금(lock)은 보유되지 않으며, 커서로부터의 재개는 비어 있지 않은 버킷에 대한 함수의 기존 동작입니다. copy_to_user() 이후 per-bucket 루프에도 동일한 호출을 추가합니다. 이 지점에서는 모든 잠금이 해제되었습니다. cond_resched_rcu()만으로는 충분하지 않습니다: bpf_prog_active가 활성화된 상태에서 대기(sleeping)하면 해당 CPU에서의 tracing 프로그램이 호출을 조용히 건너뛰게 됩니다.
단순한 cond_resched()도 충분하지 않습니다. 커밋 7dadeaa6e851("sched: Further restrict the preemption modes") 이후 arm64와 x86에서 제공해 온 유일한 모델인 PREEMPT 및 PREEMPT_LAZY 하에서는 이것이 no-op(무작위 작업)입니다. 또한 어떤 모델에서도 Tasks RCU quiescent state가 아닙니다: reschedule는 preempt로 간주됩니다. 순회 중인 태스크(holdout)는 syscall이 반환될 때까지 synchronize_rcu_tasks()를 호출하는 모든 프로세스, ftrace 및 BPF trampoline teardown을 포함하여 스톨(stall)시킵니다 [1].
cond_resched_tasks_rcu_qs()가 이에 대한 일반적인 도구입니다 [2]. 이는 각 yield 시 quiescent state를 보고하며 PREEMPT_NONE 및 PREEMPT_VOLUNTARY 커널에서 cond_resched()가 수행하는 것처럼 reschedule도 수행합니다.
If you want to get the best quality for vulnerability data then you always have to consider VulDB.