🇰🇷 한글 설명
Linux 커널의 BPF 기능 중 __bpf_get_stack 함수에서 선점(preemption)을 비활성화하지 않아 발생하는 취약점입니다. 특정 조건에서 다른 작업이 CPU 버퍼를 재사용하여 trace->nr 값을 조작할 수 있으며, 이로 인해 메모리 경계를 벗어난 쓰기(Out-of-bounds write)가 발생할 수 있습니다.
💡 쉬운 설명
컴퓨터가 작업을 처리하는 도중 다른 작업이 끼어들어 데이터를 몰래 바꿔치기할 수 있는 허점이 발견되었습니다. 이로 인해 시스템의 중요한 메모리 영역이 잘못된 데이터로 덮어씌워질 위험이 있습니다.
🇺🇸 원문 (English)
In the Linux kernel, the following vulnerability has been resolved:
bpf: Disable preemption in __bpf_get_stack
get_perf_callchain() returns a per-CPU perf_callchain_entry buffer and
releases its recursion slot via put_callchain_entry() before returning,
so nothing keeps the entry reserved while __bpf_get_stack() consumes
it below.
A preemptible BPF program (e.g. a non-sleepable raw tracepoint program
on a PREEMPT kernel, which runs under migrate_disable() but not
preempt_disable()) can be scheduled out between obtaining the entry
and the copy. Another task scheduled on the same CPU then reuses the
same per-CPU buffer and overwrites trace->nr with a larger value.
copy_len is then computed from the inflated trace->nr and can exceed
the caller's buffer, causing an out-of-bounds write in the memcpy()
and in the build_id path.
The rcu_read_lock() taken here alone does not prevent this. It is
only taken on the may_fault path, and under CONFIG_PREEMPT_RCU it does
not disable preemption; it merely keeps perf's callchain buffer array
alive (freed via call_rcu()) and does nothing to stop another task
from reusing the entry.
Disable preemption around obtaining the callchain entry and copying
it into the caller's buffer, so the entry cannot be reused underneath
us and trace->nr stays bounded by max_depth. Build ID resolution may
fault and is therefore deferred until after preemption is re-enabled;
by then the instruction pointers have already been copied into buf,
so it operates only on that private copy. Note, preempt_disable() also
subsumes the buffer-lifetime guarantee the rcu_read_lock() provided,
since a preempt-disabled section is an RCU read-side critical section
for the callchain buffers' call_rcu() reclaim.
[ changed Fixes: commit ]
📍 영향받는 시스템
Linux Kernel (PREEMPT 설정이 활성화된 환경)
⚔️ 공격 벡터
로컬 권한을 가진 공격자가 BPF 프로그램을 실행하여 CPU 버퍼 재사용을 유도하고 메모리 오버플로우를 유발
🛡️ 대응 방법
커널 패치를 적용하여 __bpf_get_stack 함수 내에서 callchain entry 사용 시 선점을 비활성화하도록 업데이트
🔧 검증 코드
출력된 커널 버전이 해당 취약점이 수정된 최신 패치 버전인지 확인