Vghost: dos kernels en mi Ubuntu y ninguno lo arregla

Publicado 12 min de lectura
Ver imagen del artículo
Greg Kroah-Hartman habla junto a un atril en la LinuxCon Europe 2014

El jueves 15, a las 06:06 UTC, unattended-upgrades instaló en el servidor web el kernel 6.8.0-147. Esta mañana he buscado en su registro de cambios el arreglo de Vghost, el fallo de vhost que Tencent publicó el lunes. No está. Tampoco en el 6.8.0-138, que es el que sigue arrancado.

Vghost es CVE-2026-74580. Según el informe de Tencent, quien pueda abrir /dev/vhost-net o /dev/vhost-vsock puede hacerse root, y con cierta configuración una máquina virtual llega a escribir en la memoria del QEMU que la ejecuta. Red Hat y Amazon lo corrigieron en agosto. Ubuntu 24.04, a 16 de octubre, todavía no.

Esquema: qué pasa al abrir /dev/vhost-net en Ubuntu 24.04, de los permisos del nodo a la carga del módulo vhost, y dónde corta el bloqueo propuesto
Qué pasa al abrir /dev/vhost-net aquí y dónde lo corta la propuesta. Esquema propio.

Qué he medido y en qué máquina

No puedo reiniciar en un kernel que no existe, pero sí saber quién puede abrir esos dos ficheros y cómo impedir que el módulo se cargue. Lo Probado lo ejecuté el 16 de octubre de 2026, entre las 04:27 y las 04:40 UTC, en el servidor web: Ubuntu 24.04.5 LTS, kernel 6.8.0-138.

Todo ha sido lectura, más modprobe -n, que enseña lo que haría sin cargar nada. Lo que sale del informe de Tencent, del commit o de los avisos de cada distribución va como Revisado (lo explico en cómo pruebo y reviso las guías).

[WARN] Hay una prueba de concepto pública en GitHub, enlazada por The Hacker News; su primer commit es del día 13. No la he ejecutado: en un servidor con webs de verdad, no. Quien quiera verla, en una máquina virtual de usar y tirar.

Qué es Vghost, en corto

vhost es la parte del kernel que acelera la red, el almacenamiento y el vsock de las máquinas virtuales. QEMU le dice dónde están los anillos de cada cola virtio, y vhost guarda en caché la traducción de esas direcciones para no repetirla en cada acceso.

El commit del arreglo lo explica: la caché se vacía en varios casos, pero no cuando VHOST_SET_VRING_ADDR cambia los anillos ni cuando VHOST_SET_VRING_NUM cambia su tamaño. vhost sigue usando la traducción vieja y accede a memoria fuera de la región que de verdad está mapeada.

No privilege is required beyond opening a device node: several distributions ship /dev/vhost-vsock and /dev/vhost-net mode 0666 (the systemd default udev rules), while others use 0660 root:kvm.

Tencent Zhuque Lab, informe de Vghost (12/10/2026)

Viene de lejos: la caché entró en Linux 4.11 (2017) y un cambio de la 5.9 (2020) aplazó la comprobación de direcciones. Según Tencent, su sistema Corvus AI lo encontró en dos horas. El parche, de Jun Yang, lleva la línea Assisted-by: tencentos-corvus-ai:kimi-k3.

  • Root en el anfitrión. Basta con abrir uno de los dos nodos. Tencent lo reprodujo en Ubuntu 26.04, RHEL 9.8, Amazon Linux 2023, Azure Linux 3.0 y Oracle Linux 10.2. En Ubuntu necesitó un usuario del grupo kvm; en los otros cuatro, cualquiera.
  • Salir de la máquina virtual. Exige un IOMMU virtual con iommu_platform y vhost en modo device-IOTLB. Para ese camino no hay arreglo provisional, según The Hacker News: solo el kernel corregido.

Dónde está el parche y dónde no

El registro del CVE da el arreglo en siete ramas estables, de la 5.10.265 a la 7.1.9. La 6.8 de Ubuntu no está entre ellas ni entre las ramas longterm de kernel.org: no hay una 6.8.x corregida que tomar. Depende de que Canonical lo meta en la suya.

2026-08-04

Arreglo en la rama principal

Commit de845981, de Jun Yang (fechado el día 3), firmado también por Michael S. Tsirkin, mantenedor de vhost.

2026-08-20

RHEL 9 corregido

RHSA-2026:57252, kernel 5.14.0-687.41.1, según la ficha de Red Hat.

2026-08-21 y 31

CVE publicado; Amazon Linux corregido

El 31, los kernels de Amazon Linux 2 y 2023, según su ficha del CVE.

2026-10-12 y 13

Informe de Tencent; Ubuntu, pendiente

El rastreador de Ubuntu marca la 24.04 «Vulnerable, work in progress»; sus datos dejan el arreglo pendiente para 6.8.0-148.148. La 22.04 ya lo tiene.

2026-10-15 06:06 UTC

Instalado aquí el 147

Lo trae unattended-upgrades. No lleva el arreglo.

Las notas no cuadran: 8,8 sobre 10 para el equipo de CVE del kernel, 8,7 para Red Hat, 7,8 para Amazon; Ubuntu le da prioridad media. Para el registro del CVE, el atacante típico es la cuenta del grupo kvm con la que libvirt arranca QEMU, o un huésped malicioso.

Mi kernel: el que corre y el que espera

Busqué el arreglo en los dos registros de cambios, por el CVE y por el asunto del commit, por si Ubuntu lo hubiera metido sin nombrarlo:

kernel.sh
BASH
# El que corre y los que estan instalados (ii), no los que dejaron config
uname -r
dpkg -l 'linux-image-6.8.0-*' | awk '/^ii/{print $2, $3}'

# El arreglo, por CVE o por el asunto del commit
for v in 138 147; do
  f=/usr/share/doc/linux-modules-6.8.0-$v-generic/changelog.Debian.gz
  echo "$v: $(zgrep -c -e CVE-2026-74580 -e 'vring metadata cache' $f)"
done

# 6.8.0-138-generic
# linux-image-6.8.0-138-generic 6.8.0-138.138
# linux-image-6.8.0-147-generic 6.8.0-147.147
# 138: 0
# 147: 0

Cero en los dos. Ubuntu lo espera en el 148, y la API de Launchpad no devuelve todavía ningún paquete con ese número en el archivo. Reiniciar hoy me llevaría al 147: un kernel más nuevo con el mismo fallo.

Y una corrección. En la entrada de curl dije que esperaba reinicio el kernel 146. Ya ni existe: unattended-upgrades lo desinstaló el día 15 al meter el 147. Instalado sigue sin ser lo mismo que en uso, como en la de algif_aead.

Quién puede abrir /dev/vhost-net aquí

Lo que pide la prueba de concepto es abrir el nodo. Así que miré quién puede, y lo intenté con un usuario sin privilegios:

quien-abre.sh
BASH
# Permisos, dueno y grupo de los dos nodos
stat -c '%n %a %U:%G' /dev/vhost-net /dev/vhost-vsock

# Quien esta en kvm: miembros y usuarios con kvm de grupo principal (993)
getent group kvm
awk -F: '$4==993' /etc/passwd

# Un usuario sin privilegios intenta abrirlo
sudo -u nobody python3 -c 'import os; os.open("/dev/vhost-net", os.O_RDWR)'

# Modulos vhost cargados despues del intento
lsmod | grep -c '^vhost'

# /dev/vhost-net 660 root:kvm
# /dev/vhost-vsock 660 root:kvm
# kvm:x:993:
# PermissionError: [Errno 13] Permission denied: '/dev/vhost-net'
# 0

Solo root. El grupo kvm está vacío, y el usuario normal se lleva un EACCES antes de que se cargue nada. Aquí, hoy, Vghost no le sirve a nadie para subir a root. Pero el módulo está a un open() de root de cargarse.

138

KERNEL EN USO

sin el arreglo

147

INSTALADO

tampoco lo lleva

0

EN EL GRUPO KVM

solo root abre

0

MÓDULOS VHOST

cargados ahora

Por qué 0660 aquí y 0666 en otros

Los permisos los pone udev, desde 50-udev-default.rules, donde /dev/kvm y los dos nodos de vhost toman el mismo modo. systemd lo trae a 0666 por defecto (la opción dev-kvm-mode de la v255), y Ubuntu lo compila con 0660, igual que Debian.

Eso cuadra con la tabla de Tencent: el /dev/vhost-vsock de Ubuntu 26.04 era 0660 y el de las otras cuatro, 0666. Y quién entra en kvm depende de lo que instales: el postinst de libvirt-daemon-system, que bajé sin instalar, crea libvirt-qemu con kvm como grupo principal.

[INFO] Los dos nodos tienen fecha del 15 de octubre a las 06:06:21, como /dev/kvm y /dev/fuse: un segundo después de que unattended-upgrades actualizara udev, systemd reinició systemd-udevd. Por eso no propongo un chmod a mano; aquí udev rearranca sin pedir permiso.

Lo que propongo y no he aplicado

Aquí nadie usa vhost: no hay QEMU ni libvirt instalados y Docker no tiene contenedores. Lo más limpio es que no se cargue, como hizo Ubuntu con algif_aead en abril. Este es el fichero; no lo he puesto en /etc/modprobe.d, lo decide quien administra la máquina:

vghost-cve-2026-74580.conf
MODPROBE
# CVE-2026-74580 (Vghost). Este servidor no ejecuta maquinas virtuales:
# nadie necesita vhost. Hasta arrancar un kernel con el arreglo (Ubuntu
# lo espera en 6.8.0-148.148), que no se cargue ni al abrir /dev/vhost-net
# o /dev/vhost-vsock. Se bloquea tambien vhost, el nucleo donde esta el
# fallo: si no, modprobe lo carga como dependencia antes del /bin/false.
install vhost /bin/false
install vhost_net /bin/false
install vhost_vsock /bin/false
install vhost_vdpa /bin/false

La primera línea es la que importa, y la añadí después de probar sin ella: con solo las otras tres, modprobe -n enseñaba que cargaría tap, vhost_iotlb y vhost antes del /bin/false de vhost_net. El módulo con el fallo se quedaba dentro. Con ella:

en-seco.sh
BASH
# -n: solo ensena lo que haria. Sin sudo; no carga nada.
# Hoy, lo que se cargaria al abrir /dev/vhost-net
modprobe -n -v vhost_net
# insmod .../kernel/drivers/net/tap.ko.zst
# insmod .../kernel/drivers/vhost/vhost_iotlb.ko.zst
# insmod .../kernel/drivers/vhost/vhost.ko.zst
# insmod .../kernel/drivers/vhost/vhost_net.ko.zst

# Con el fichero propuesto en una copia de modprobe.d (-C)
modprobe -n -v -C ./modprobe.d char-major-10-238
# insmod .../kernel/drivers/net/tap.ko.zst
# insmod .../kernel/drivers/vhost/vhost_iotlb.ko.zst
# install /bin/false
# install /bin/false

char-major-10-238 es el alias de vhost_net en modules.alias que corresponde al número del nodo. Contra el kernel 147, con -S, dio lo mismo. Red Hat, en su ficha, propone solo esa primera línea, con /bin/true; prefiero /bin/false, como el bloqueo de kmod, para que el fallo se vea.

Donde el nodo salga 0666, o haya en kvm cuentas que no lo necesitan, Tencent recomienda quitar el acceso. Esta regla debería dejarlo solo para root desde el arranque (para eso lleva static_node, como la original), pero de ella solo he comprobado la sintaxis:

99-vhost-solo-root.rules
UDEV
# En /etc/udev/rules.d/. No aplicada en este servidor: aqui kvm esta vacio.
KERNEL=="vhost-net", GROUP="root", MODE="0600", OPTIONS+="static_node=vhost-net"
KERNEL=="vhost-vsock", GROUP="root", MODE="0600", OPTIONS+="static_node=vhost-vsock"

# udevadm verify 99-vhost-solo-root.rules
# 1 udev rules files have been checked.
#   Success: 1
#   Fail:    0

Nada de esto descarga un módulo ya cargado: para eso Red Hat indica modprobe -r, con las máquinas virtuales paradas. Y con huéspedes, la regla no sirve contra el escape (QEMU necesita el nodo); bloquear vhost entero sí corta ese camino, al precio que avisa Red Hat: red y discos virtuales más lentos, o máquinas que no arrancan.

Comprobación

Este guion junta lo anterior y solo lee. Hoy da esto; con el fichero puesto, la última línea debería decir install /bin/false:

vghost-comprobar.sh
SH
#!/bin/sh
# Exposicion a CVE-2026-74580 (Vghost) en esta maquina. Solo lee: no abre
# los dispositivos ni carga modulos. Sin root ve casi todo.
echo "kernel en uso: $(uname -r)"
for n in /dev/vhost-net /dev/vhost-vsock; do
  # 0666 = cualquier usuario puede abrirlo; 0660 = solo el grupo
  [ -e "$n" ] && stat -c '%n %a %U:%G' "$n" || echo "$n no existe"
done
# Quien puede abrirlos por grupo: miembros secundarios y primarios
g=$(stat -c %G /dev/vhost-net 2>/dev/null)
gid=$(getent group "$g" | cut -d: -f3)
echo "grupo $g, miembros: $(getent group "$g" | cut -d: -f4)" \
     "primarios: $(awk -F: -v g="$gid" '$4==g{printf "%s ", $1}' /etc/passwd)"
# Si el modulo ya esta cargado, bloquearlo en modprobe no basta
echo "modulos vhost cargados: $(lsmod | awk '/^vhost/{printf "%s ", $1}')"
# Lo que haria modprobe al abrir /dev/vhost-net (en seco)
echo "modprobe -n vhost_net: $(modprobe -n -v vhost_net 2>&1 | tail -1)"

# kernel en uso: 6.8.0-138-generic
# /dev/vhost-net 660 root:kvm
# /dev/vhost-vsock 660 root:kvm
# grupo kvm, miembros:  primarios:
# modulos vhost cargados:
# modprobe -n vhost_net: insmod /lib/modules/6.8.0-138-generic/kernel/drivers/vhost/vhost_net.ko.zst

Vuelta atrás

De hoy no hay nada que deshacer: solo he leído, y el paquete de libvirt sigue sin instalar en un directorio de trabajo. Deshacer la propuesta es borrar el fichero de /etc/modprobe.d, sin reiniciar. La regla de udev se quita igual; sus permisos se van en el siguiente arranque.

Con el 148 arrancado, el fichero sobra. Que no se quede olvidado como el de algif_aead, ahí desde el 30 de abril sobre un kernel que ya no lo necesita.

Qué no he probado

  • La prueba de concepto, ni aquí ni en otra máquina.
  • Abrir /dev/vhost-net como root: cargaría el módulo, que es justo lo que no quería.
  • El escape desde una máquina virtual. Aquí no hay ninguna.
  • El kernel 6.8.0-148: no está publicado.
  • La regla de udev en un arranque real, ni si gana siempre a la de 50-udev-default.rules.
  • Contenedores con acceso a /dev/vhost-*. En este servidor no hay ninguno.
  • El homelab, la Machinist de la comparativa de AMD e Intel: no lo he mirado.
  • Nada en ARM ni en otra versión de Ubuntu.

Me queda una duda. La prioridad media de Ubuntu cuadra con un servidor como este, con kvm vacío. En una máquina con libvirt y huéspedes de terceros no la entiendo: ahí el 148 corre prisa. Más guías así en el hub de Ubuntu y Linux.

Actualización del 2 de noviembre de 2026: otro fallo de kernel sin arreglo en Ubuntu 24.04, el CVE-2026-98432, tiene una mitigación de Red Hat que probé aparte: la regla de nftables, probada.

Compartir esta entrada WhatsApp X / Twitter LinkedIn Reddit Telegram Bluesky Email
Siguiente comando: volver al archivo o pulsa Ctrl + K
Hilo abierto

La conversación empieza aquí

Escribir un comentario

Nadie ha escrito todavía. Si lo has probado en tu máquina, cuenta qué te salió: otra versión u otro resultado también ayudan.

Escribe tu comentario

Si planteas un problema técnico, di sistema, versión, qué esperabas y qué has probado. Respeto y cero spam: tu correo no se publica.

0 caracteresCtrl + Enter para enviar

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.