
Qubes OS se vende como el sistema operativo más seguro del mundo. Su modelo se basa en compartmentalización: cada tarea corre en una VM separada, y dom0 —el dominio administrativo— nunca toca datos no confiables. Excepto que esta semana descubrieron que sà los tocaba, y de la peor forma posible.
El bug
El boletÃn de seguridad QSB-118, publicado el 29 de agosto, describe una vulnerabilidad de ejecución arbitraria de código en dom0. La causa es casi ridÃcula: la función qvm-copy-to-vm, que copia archivos desde dom0 hacia una qube, usa un protocolo llamado qfile que incluye confirmación de transferencia. Esa confirmación contiene el nombre del archivo y un código de error.
Cuando hay un error, dom0 muestra un diálogo gráfico con el nombre del archivo problemático. Para limpiar el nombre, existe sanitize_remote_filename(), que reemplaza caracteres no imprimibles y comillas dobles. Pero se le olvidó algo fundamental: los metacaracteres de shell.
El nombre saneado se pasa a display_error(), que construye un comando tipo kdialog --sorry 'texto: NOMBRE_ARCHIVO' y lo ejecuta con system(). Si una qube comprometida envÃa un nombre de archivo como foo'; comando_maligno; echo ', dom0 ejecuta ese comando con privilegios completos. Fin del aislamiento. Fin de la seguridad.
Por qué importa
Esto no es un bug menor en una herramienta opcional. Es una rotura del contrato fundamental de Qubes: dom0 no debe poder ser comprometido desde una qube. Toda la arquitectura de seguridad depende de que dom0 sea un territorio sagrado. Si una VM cualquiera puede inyectar comandos en dom0, tienes lo mismo que un sistema operativo normal con un atacante teniendo root. Para eso no necesitas Qubes.
Lo que más me llama la atención es el contraste entre dos piezas de código en el mismo proyecto. La versión VM de la función de error usa execlp() —que no pasa por un shell— y además hace setuid() antes de ejecutar. La versión dom0 usa system() sin ningún tipo de escape. Misma función, dos implementaciones, una segura y otra no. Asà de frágil es la seguridad.
La lección
Si escribes código que procesa entrada de una fuente no confiable, nunca uses system(). Usa exec* con argumentos separados. Si no puedes evitar el shell, escapa todo con la función correcta del lenguaje. Y si estás saneando entrada para evitar inyección, tu lista de caracteres prohibidos debe ser una whitelist, no una blacklist. Qubes bloqueó comillas dobles pero dejó pasar punto y coma, pipe, backticks, signos de dólar. Esa es la diferencia entre seguridad e ilusión de seguridad.
La vulnerabilidad afecta a todas las versiones de Qubes OS. El parche está en el paquete qubes-core-dom0-linux versión 4.3.22. Si usas Qubes, actualiza ahora. Si no usas Qubes pero escribes código que recibe input del exterior, revisa tus llamadas a system(). El bug fue descubierto por alguien que firma como Tim C., y es de esos hallazgos que te hacen replantearte cuántas cosas similares existen en código que usas todos los dÃas sin saberlo.
Fuente de inspiración: QSB-118: Dom0 arbitrary code execution in qvm-copy-to-vm error reporting
