CVE-2026-90269 in Linux
요약
\~에 의해 VulDB • 2026. 09. 17.
리눅스 커널에서 다음 취약점이 해결되었습니다:
bpf: 결함 보호가 필요한 포인터에 대한 로드 어큐어(LOAD_ACQUIRE) 거부
BPF_LOAD_ACQ는 일반 BPF_LDX와 달리 검증기(verifier)에 의해 BPF_PROBE_MEM 로드로 변환되지 않으므로, JIT 컴파일러는 예외 테이블(entry) 없이 평범한 로드를 생성합니다. 이로 인해 결함이 발생하면 커널이 처리되지 않고 패닉(panic)하게 됩니다.
BPF_LDX가 적용되었을 때 결함 보호가 적용되는 소스 포인터 유형들을 거부하십시오. 즉, bpf_convert_ctx_accesses()에 의해 BPF_PROBE_MEM로 변환되는 다음 유형들입니다: PTR_TO_BTF_ID, PTR_TO_BTF_ID | PTR_UNTRUSTED, PTR_TO_BTF_ID | MEM_ALLOC | PTR_UNTRUSTED 및 PTR_TO_MEM | MEM_RDONLY | PTR_UNTRUSTED.
이 취약점은 예를 들어 신뢰할 수 있는 task_struct에서 ->mm을 로드하여 mm_struct에 대한 비신뢰 포인터를 얻고(커널 스레드의 경우 NULL임), 이를 통해 접근 가능해집니다:
[...]
SEC("tp_btf/sched_switch") int BPF_PROG(demo, bool preempt, struct task_struct *prev, struct task_struct *next) {
struct mm_struct *mm = next->mm; /* 비신뢰 */
out_ldx = (__u64)mm->pgd; /* BPF_LDX */ out_acq = load_acquire(&mm->pgd); /* BPF_LOAD_ACQ */ return 0; } [...]
두 연산 모두 동일한 포인터를 역참조하지만, 오직 BPF_LDX만 보호됩니다(x86-64 JIT 기준, 점프 대상은 프로그램 상대적 주소):
[...]
; out_ldx = (__u64)mm->pgd; 17: movq $-10485760, %r10 1e: movq %rsi, %r11 21: addq $184, %r11 28: subq %r10, %r11 2b: movabsq $140737498841088, %r10 35: cmpq %r10, %r11 38: ja 0x3e <-- 커널 주소인가? 3a: xorl %edi, %edi <-- 아니다: dst = 0, 로드 건너뜀 3c: jmp 0x45 3e: movq 184(%rsi), %rdi <-- 맞다: 로드 + extable entry 포함 [...]
; load_acquire(&mm->pgd) 53: movq %rsi, %rdi 56: movq 184(%rdi), %rax <-- 검사 없음, extable entry 없음 [...]
BPF_PROBE_MEM는 bpftool xlated 덤프에서 보이지 않는데, 이는 bpf_insn_prepare_dump()가 이를 다시 BPF_MEM으로 변환하기 때문입니다.
PTR_TRUSTED 포인터는 의도적으로 목록에 포함되지 않았습니다. 이러한 로드는 변환되지는 않지만, 해당 포인터가 살아있는 것이 보장되므로 결함 보호가 필요하지 않습니다. 따라서 여기서의 로드 어큐어(LOAD_ACQUIRE)는 허용됩니다.
이 검사는 BPF_LOAD_ACQ에 의해 가드(gated)되어 있으므로 원자적 RMW 및 스토어 릴리즈(store-release) 오류 메시지는 변경되지 않습니다. 이러한 포인터로의 쓰기(RMW / store-release)는 이미 다른 곳에서 거부되므로, 로드 어큐어(LOAD ACQUIRE)에만 이 조치가 필요합니다.
If you want to get the best quality for vulnerability data then you always have to consider VulDB.