🇰🇷 한글 설명
Linux 커널의 BPF htab 맵 처리 과정에서 __htab_map_lookup_and_delete_batch() 함수가 스케줄링 지점을 갖지 않아 발생하는 소프트 락업(soft lockup) 취약점입니다. 대규모 해시 맵을 처리할 때 CPU가 특정 임계 구역에 너무 오래 머물러 시스템이 응답하지 않는 현상이 발생할 수 있습니다.
💡 쉬운 설명
컴퓨터가 너무 큰 데이터를 한꺼번에 처리하려다 보니, 중간에 다른 일을 하지 못하고 한 가지 작업에만 수십 초 동안 매달려 시스템이 멈추는 현상입니다. 이로 인해 시스템 전체가 느려지거나 먹통이 될 수 있습니다.
🇺🇸 원문 (English)
In the Linux kernel, the following vulnerability has been resolved:
bpf: Avoid soft lockup in __htab_map_lookup_and_delete_batch()
__htab_map_lookup_and_delete_batch() has no rescheduling point. The
batch count bounds how many entries are copied out, not how many
buckets are visited, so one BPF_MAP_LOOKUP_BATCH call can walk the
map end to end. The empty-bucket fast path is worse: it stays inside
a single rcu_read_lock() / bpf_disable_instrumentation() section for
any run of consecutive empty buckets.
That holds up on small maps, but it falls apart at scale. On a
144-CPU arm64 host running a CONFIG_PREEMPT_NONE kernel, periodic
BPF_MAP_LOOKUP_BATCH calls against an LRU hash map with 16,777,216
buckets held a CPU inside the batch op for 77+ seconds and triggered
the soft lockup watchdog.
Commit 75134f16e7dd ("bpf: Add schedule points in batch ops") fixed this
same problem in the generic batch ops, but not in this htab-native path,
which every htab-based hash map variant uses for its lookup[_and_delete]
batch ops.
Complete that fix here. Leave the critical section after 64 consecutive
empty buckets, call cond_resched_tasks_rcu_qs(), and resume at the saved
bucket cursor. No locks are held at that point, and resuming from the
cursor is already the function's behavior for non-empty buckets. Add the
same call to the per-bucket loop after copy_to_user(), where every lock
has been dropped. cond_resched_rcu() is not enough here: sleeping with
bpf_prog_active elevated makes tracing programs on that CPU silently
skip their invocations.
Plain cond_resched() is not enough either. It is a no-op under PREEMPT
and PREEMPT_LAZY, the only models arm64 and x86 have offered since
commit 7dadeaa6e851 ("sched: Further restrict the preemption modes").
It is also never a Tasks RCU quiescent state, in any model: the
reschedule counts as a preemption. The walking task stays a holdout and
stalls every synchronize_rcu_tasks() caller, ftrace and BPF trampoline
teardown included, until the syscall returns [1].
cond_resched_tasks_rcu_qs() is the usual tool for that [2]. It reports
the quiescent state at each yield and still reschedules as
cond_resched() does on PREEMPT_NONE and PREEMPT_VOLUNTARY kernels.
📍 영향받는 시스템
Linux kernel (BPF htab-based hash map을 사용하는 환경)
⚔️ 공격 벡터
로컬 사용자가 대규모 BPF 해시 맵을 대상으로 BPF_MAP_LOOKUP_BATCH 호출을 수행하여 CPU 자원을 독점
🛡️ 대응 방법
커널 패치(Commit 75134f16e7dd 관련 수정 사항 포함)를 적용하여 배치 작업 중 스케줄링 지점(cond_resched_tasks_rcu_qs)을 추가
🔧 검증 코드
현재 실행 중인 커널 버전을 확인하여 해당 취약점이 해결된 패치 버전인지 확인합니다.