🇰🇷 한글 설명
Linux 커널의 x86/kprobes에서 CS CALL 명령어를 프로브할 때 시스템 충돌이 발생하는 취약점입니다. eBPF 도구가 특정 함수 내의 CS CALL 명령어를 프로브할 때, 명령어 길이를 잘못 계산하여 잘못된 복귀 주소로 점프함으로써 커널 패닉을 유발합니다.
💡 쉬운 설명
시스템의 동작을 관찰하는 도구가 특정 명령어를 잘못 읽어서 컴퓨터가 갑자기 멈추거나 꺼지는 현상입니다. 명령어의 길이를 실제보다 짧게 계산하여 엉뚱한 위치로 실행 흐름이 튀기 때문에 발생합니다.
🇺🇸 원문 (English)
In the Linux kernel, the following vulnerability has been resolved:
x86/kprobes: Fix crash when probing CS CALL instructions
When using eBPF to probe CS CALL instructions within a function,
a crash can be triggered.
The eBPF tool probes offset 257 of the __hrtimer_run_queues()
function:
<__hrtimer_run_queues+249>: nopl 0x0(%rax,%rax,1)
<__hrtimer_run_queues+254>: mov %r14,%rdi
<__hrtimer_run_queues+257>: cs call <__x86_indirect_thunk_r12>
<__hrtimer_run_queues+263>: mov %eax,%r12d
<__hrtimer_run_queues+266>: xchg %ax,%ax
<__hrtimer_run_queues+268>: mov %r13,%rdi
Which triggers this crash:
BUG: unable to handle page fault for address: 00000000000f41c9
#PF: supervisor write access in kernel mode
#PF: error_code(0x0002) - not-present page
PGD 0 P4D 0
Oops: 0002 [#1] SMP NOPTI
CPU: 1 PID: 0 Comm: swapper/1 Kdump: loaded Tainted: P
RIP: 0010:__hrtimer_run_queues+0x106/0x230
Note that __hrtimer_run_queues+0x106 is __hrtimer_run_queues+262, which is
at the 6th byte of the above CS CALL instruction. Since the CS CALL
instruction occupies 6 bytes, the exception occurred in the middle of that
call instruction.
The root cause is that when using eBPF tools to probe in the middle of a
function, a kprobe with INT3 is used as the underlying implementation.
During single-step emulation of the original CALL instruction,
int3_emulate_call() assumes that the probed CALL instruction is 5 bytes
long. However, the actual CS-prefixed CALL instruction occupies 6 bytes,
so it constructs an incorrect exception return address. When the CPU
returns from the kprobe handler, the next instruction to be executed is at
the address of the last byte of that CS CALL instruction. Coincidentally,
starting from that address, the CPU fetches and decodes a completely
different instruction, which ultimately triggers a kernel crash.
Fix the issue by using the actual instruction length obtained from
the instruction decoder when constructing the exception return
address, rather than relying on the hardcoded CALL_INSN_SIZE macro.
[ mingo: Refined the changelog ]
📍 영향받는 시스템
Linux kernel (x86 architecture using kprobes/eBPF)
⚔️ 공격 벡터
eBPF 도구를 사용하여 특정 CS CALL 명령어가 포함된 커널 함수를 프로브할 때 발생 (로컬 권한 필요)
🛡️ 대응 방법
커널의 명령어 디코더를 사용하여 실제 명령어 길이를 반영하도록 커널 패치를 적용해야 합니다.
🔧 검증 코드
현재 실행 중인 커널 버전을 확인하여 해당 취약점이 수정된 최신 패치 버전인지 확인합니다.
💻 영향받는 소프트웨어
NVIDIA Cloud Gaming Guest Driver for Linux