Compró GPUs para ir más rápido. Ahora está descubriendo que también pueden acelerar su peor día: exposición de datos, vecinos ruidosos y incidentes del tipo «¿por qué la salida de mi modelo es distinta?» incluidos.
La verdad incómoda: las GPUs modernas se parecen mucho a como eran las CPUs justo antes de que Spectre/Meltdown se convirtieran en palabras recurrentes en los canales de incidentes. Se comparten, se optimizan para el rendimiento, están llenas de comportamientos microarquitectónicos que nadie documenta y están impulsadas por un enorme código privilegiado en el kernel.
Cómo sería un momento «Spectre para gráficos»
Spectre no fue solo «un bug de CPU». Fue una lección sistémica: si construye características de rendimiento que dependen de comportamientos dependientes de secretos, alguien acabará convirtiendo ese comportamiento en una primitiva de lectura.
Las GPUs están llenas de comportamientos dependientes de secretos. También están llenas de atajos «primero el rendimiento» que son invisibles hasta que ejecuta código no confiable junto a cargas de trabajo sensibles.
Un momento «Spectre para gráficos» no sería necesariamente un único CVE que lo rompa todo de la noche a la mañana. Lo más probable es que sea un patrón:
- Un canal lateral microarquitectónico (temporización de caché, conflictos en bancos de memoria compartida, efectos de ocupación, artefactos en la programación de instrucciones) que filtre algo valioso: pesos de modelos, prompts, embeddings, claves criptográficas o características de datos.
- Fuga entre inquilinos en nubes o clústeres compartidos (nodos GPU en Kubernetes, particiones Slurm, granjas VDI o plataformas MLOps) donde dos clientes comparten una GPU o rutas de memoria del host.
- La realidad de «el controlador como extensión del kernel» donde un bug en un enorme módulo del kernel de GPU se convierte en la forma más fácil de escapar de un contenedor en la máquina.
- Radio de explosión operacional porque las mitigaciones cuestan rendimiento real, y el negocio intentará negociar con la física.
El mejor modelo mental no es «un hacker leyendo registros de GPU». Es «un vecino infiriendo sus secretos midiendo recursos compartidos», más «un parche del proveedor que cambia las características de rendimiento y rompe sus garantías de reproducibilidad».
Si gestiona infraestructura GPU multi-inquilino hoy, asuma que tres cosas son ciertas:
- Alguien encontrará una vía de filtración que usted no conocía.
- Su historia de aislamiento será en parte contractual («no hacemos eso») y en parte técnica («no podemos hacer eso»).
- La mayoría de las mitigaciones serán feas: programación, particionado y desactivar ingeniosidades.
Hechos e historia: el camino hacia problemas con forma de GPU
Los hechos importan porque evitan que tratemos la seguridad de GPU como folklore. Aquí hay puntos de contexto concretos: cortos, aburridos y por eso útiles.
- Las GPUs evolucionaron de canalizaciones de función fija a cómputo general durante aproximadamente dos décadas, y los modelos de seguridad se quedaron atrás frente a la nueva realidad de «aquí se ejecuta código no confiable».
- CUDA (2007) normalizó el cómputo en GPU en sistemas mainstream, lo que también significó que la pila de controladores se convirtió en un objetivo de alto valor: grande, privilegiada y expuesta a entradas controladas por el usuario.
- Meltdown/Spectre (públicos en 2018) replantearon las «características de rendimiento» como superficie de ataque y convirtieron los canales laterales en una preocupación de seguridad de primera clase, no en un hobby académico.
- Las GPUs modernas comparten en gran medida recursos en chip (cachés L2, controladores de memoria, telas de interconexión) entre contextos; compartir es genial para la utilización y terrible para «no dejes que mi vecino aprenda cosas».
- La memoria de GPU a menudo la gestiona el controlador + runtime en lugar de tablas de páginas aplicadas por hardware de la forma que tranquiliza a los ingenieros de CPU; incluso cuando existe traducción de direcciones, los detalles difieren según la arquitectura y el modo.
- SR-IOV y vGPU hicieron normal el time-sharing de GPU en ofertas empresariales VDI y en la nube, aumentando las rutas donde los datos pueden filtrarse a través de límites virtuales.
- El particionado estilo MIG es un gran avance (rebanadas dedicadas de cómputo + memoria), pero no es una pegatina mágica de «no compartir nada»; algunos componentes permanecen compartidos y el firmware sigue siendo firmware.
- DMA de GPU es poderosa por diseño: el dispositivo puede leer/escribir memoria del host a alta velocidad. Sin una configuración correcta de IOMMU, esencialmente ha conectado un motor de corrupción de memoria muy rápido al bus PCIe.
- Los controladores de GPU suelen ser de los módulos de kernel más grandes en hosts Linux, lo que aumenta la superficie de errores y hace que la cadencia de parches sea un problema de fiabilidad, no solo de higiene de seguridad.
Nada de esto prueba que habrá un único «GPU Meltdown» catastrófico. Sí prueba que existen las precondiciones: recursos compartidos, comportamiento opaco, código privilegiado e incentivos masivos para optimizar.
Modelo de amenaza: qué se rompe realmente en producción
Definamos «Spectre para gráficos» en términos operativos. No necesita un paper. Necesita saber qué temer y qué ignorar.
Modelo de amenaza A: nodo GPU multi-inquilino
Dos cargas comparten la misma GPU física a lo largo del tiempo (time-slicing), o comparten el mismo nodo con passthrough/vGPU, o comparten la ruta de memoria de la CPU del host vía memoria fijada y DMA.
El atacante controla una carga, la víctima es otra.
Objetivo: inferir secretos (pesos de modelos, propiedades de datos de entrada o claves) usando canales laterales o estado residual.
Modelo de amenaza B: código GPU no confiable dentro de un contenedor
Un contenedor ejecuta CUDA, ROCm, Vulkan u OpenCL. Tiene acceso a /dev/nvidia* o /dev/dri*.
El controlador está en el kernel del host.
Objetivo: escapar del contenedor, obtener root o leer datos de otros inquilinos explotando un bug del controlador.
Modelo de amenaza C: código de entrenamiento «confiable» que no lo es realmente
Una librería del proveedor, una dependencia pip, un plugin de modelo o un «parche de rendimiento» ejecuta kernels de GPU y código en el host.
Nadie es malicioso; hay muchos descuidos.
Objetivo: filtración accidental o pérdida de integridad—resultados silenciosamente incorrectos o datos que quedan residentes en la memoria de la GPU.
Modelo de amenaza D: cadena de suministro y firmware
Firmware de GPU, blobs firmados, controladores de gestión y agentes de host (DCGM, daemons de persistencia, exportadores de monitoreo) forman parte de su TCB guste o no.
Si ejecuta nodos de inquilino único (un cliente por host físico, sin excepciones), puede reducir el riesgo dramáticamente.
Si comparte GPUs, está haciendo ingeniería de seguridad. Puede que no haya presupuestado para eso. Mala suerte.
Dónde ocurren las filtraciones de datos en GPU: las verdaderas líneas de falla
1) Memoria residual de GPU (la clase de «olvidamos borrar»)
La fuga más simple es también la más embarazosa: un trabajo libera memoria, otro trabajo asigna y aparecen bytes obsoletos.
En CPUs, los asignadores del SO y las políticas de zonificación de páginas reducen esto. En GPUs, el comportamiento varía según el controlador y el modo.
Para producción: asuma que la memoria residual es posible a menos que lo haya probado en su stack. «Probablemente el controlador la limpia» no es un control. Es pensamiento ilusorio con una solicitud de presupuesto adjunta.
2) Cachés compartidos, memoria compartida y temporización
Los canales laterales prosperan en recursos compartidos. Las GPUs tienen cachés L2, bancos de memoria compartida, cachés de textura (en contextos gráficos) y controladores de memoria que pueden filtrar información mediante patrones de temporización y contención.
El atacante no necesita leer su memoria directamente. Solo necesita saber cuánto tiempo tardó algo, cuántos sets de caché fueron expulsados o si se produjo un patrón de conflicto de bancos que se correlaciona con un acceso dependiente del secreto.
3) Direccionamiento virtual unificado y memoria fijada del host
UVA y la memoria fijada son características de rendimiento. También son una trampa de seguridad si no controla quién puede asignar qué y cuándo, porque amplían el alcance de la GPU a las rutas de memoria del host.
DMA sin IOMMU correcto es la historia clásica: el dispositivo puede acceder a memoria física del host más allá de lo que pretendía. A veces el «atacante» es solo un bug.
4) Superficie de ataque del controlador y runtime
La pila de controladores de GPU es un museo de capas de compatibilidad: runtime CUDA, módulo kernel, librerías en espacio de usuario, compilación JIT, compiladores de shaders, ICDs de Vulkan y más.
Es grande. Parsea entradas no confiables (kernels, shaders, PTX, SPIR-V). Históricamente ahí viven los bugs de corrupción de memoria.
Chiste #1 (breve, relevante): los controladores de GPU son como relojes antiguos—ingeniería hermosa, muchas piezas móviles y si los golpeas mal, hacen que el tiempo vaya de lado.
5) El particionado no es aislamiento a menos que pueda explicar lo que queda compartido
MIG, perfiles vGPU y políticas de programación pueden reducir el cruce, pero necesita saber qué sigue estando compartido:
motores de copia, particiones L2, controladores de memoria, rutas de interconexión y pools gestionados por firmware.
Su postura de seguridad depende de qué perillas puede ajustar y cuáles debe aceptar. Si no lo puede describir, no lo podrá defender en una auditoría—o en un postmortem.
Tres mini-historias corporativas (anonimizadas)
Mini-historia 1: El incidente causado por una suposición equivocada
Una empresa SaaS mediana desplegó nodos de inferencia con GPU para soportar clientes empresariales «traiga su propio modelo».
Hicieron cosas razonables: cada cliente tenía un namespace de Kubernetes, políticas de red, almacenamiento por inquilino y RBAC estricto.
También hicieron una cosa poco razonable: asumieron que la GPU era «solo otro dispositivo» y que los contenedores eran un límite suficiente.
Un cliente informó ver artefactos extraños y débilmente estructurados en salidas que parecían fragmentos de prompts de otros clientes.
Al principio sonó como una alucinación del modelo. El equipo de soporte lo archivó como «confusión del cliente». El cliente persistió, envió ejemplos reproducibles y de pronto cambió el tono.
La investigación interna encontró que los trabajos se programaban en la misma GPU uno tras otro. El proceso de inferencia usaba un asignador de pool de memoria en la GPU para reducir la sobrecarga de malloc/free.
En ciertas rutas de fallo (timeouts y salidas tempranas), los buffers se liberaban pero no se sobreescribían explícitamente.
Las primeras asignaciones del nuevo inquilino a veces reutilizaban esas páginas, y un endpoint de depuración (pensado para introspección del modelo) devolvía tensores intermedios crudos.
El problema no fue un canal lateral sofisticado. Fue una fuga aburrida y clásica de «remanencia de datos» con acento GPU.
La solución fue igual de aburrida: eliminar el endpoint de depuración en builds orientados a inquilinos, añadir cero obligatorio de buffers sensibles y aplicar la regla «un inquilino por GPU física» hasta que pudieran validar un modelo de aislamiento más fuerte.
La mayor lección del postmortem: habían tratado la «memoria GPU» como si se comportara como RAM privada de proceso.
No lo hacía. Y el incidente no fue causado por un atacante; lo desencadenó un cliente que prestó atención.
Mini-historia 2: La optimización que salió mal
Una fintech ejecutaba simulaciones de riesgo aceleradas por GPU durante la noche. La carga era predecible, bien controlada y no multi-inquilino.
Luego el negocio pidió «tiempos más rápidos» y «mejor utilización», y alguien sugirió mezclar trabajos analíticos ad-hoc en la misma ventana.
El equipo activó un time-slicing agresivo de GPU y empaquetó más contenedores por nodo.
También activaron un modo de rendimiento que mantenía los contextos calientes y evitaba resets entre trabajos.
La utilización mejoró en el dashboard. La latencia mejoró. Todos aplaudieron.
Dos semanas después, tuvieron un incidente de fiabilidad: los resultados de las simulaciones a veces divergían de forma sutil. No hubo crashes, solo respuestas incorrectas.
A las 3 a.m., ese es el peor tipo de error.
Causa raíz: interferencia por recursos compartidos. Los trabajos ad-hoc cambiaron la residencia de caché y la disponibilidad de ancho de banda de memoria en patrones que impactaron la estabilidad numérica.
Algunos kernels eran sensibles al orden de ejecución no determinista; otros dependían de reducciones con condiciones de carrera que eran «suficientemente buenas» cuando la GPU estaba ociosa.
Al empaquetar y hacer time-slicing, la variación en el orden de ejecución aumentó y los resultados derivaron más allá de las tolerancias aceptables.
Revirtieron la optimización, separaron cargas por pools de nodos y exigieron banderas de matemáticas deterministas para cualquier trabajo que produjera salidas reguladas.
Conclusión de seguridad: el pensamiento sobre canales laterales y el pensamiento sobre integridad son parientes. Los recursos compartidos no solo filtran; también sesgan.
Mini-historia 3: La práctica aburrida pero correcta que salvó el día
Un equipo de plataforma empresarial operaba un clúster GPU para equipos internos de ML. No eran famosos, no eran llamativos y nunca los invitaban a conferencias.
Tenían un superpoder: eran alérgicos a los «casos especiales».
Cada nodo GPU arrancaba con IOMMU habilitado, Secure Boot aplicado y una política de bloqueo del kernel.
Las versiones de controladores estaban fijadas por pool de nodos. Los despliegues de parches se hacían canary-first, con rollback automático si se movían los presupuestos de error.
Los perfiles MIG estaban estandarizados y el scheduler solo colocaba cargas con etiquetas de seguridad compatibles en GPUs compartidas.
Un trimestre, una actualización del controlador GPU introdujo una regresión que provocaba cuelgues esporádicos de GPU bajo una combinación específica de memoria fijada del host y transferencias peer-to-peer.
Los equipos de ML se molestaron porque sus entrenamientos se ralentizaron cuando el equipo de plataforma retuvo la actualización.
Pero el equipo de plataforma tenía telemetría: los nodos canary mostraron aumento de errores Xid y un repunte en errores correctables de PCIe. Detuvieron el despliegue.
Dos semanas después, salió un advisory de seguridad para la misma rama de controladores, involucrando una ruta de entrada controlada por el usuario que podía llevar a escalada de privilegios.
Ya no lo estaban ejecutando. Hicieron el parche hacia adelante con una build corregida, con las mismas puertas canary.
La moraleja: los controles aburridos no solo previenen brechas; previenen fines de semana frenéticos. Lo único mejor que una respuesta rápida a incidentes es no tener el incidente.
Tareas prácticas: comandos, salidas y decisiones (12+)
Estas no son tareas de «ejecute un scanner y rece». Son las comprobaciones duras que le dicen si su flota GPU está realmente aislada, parchada y comportándose.
Cada tarea incluye: comando, salida de ejemplo, qué significa y qué decisión tomar.
Tarea 1: Inventario de modelo GPU, controlador y runtime
cr0x@server:~$ nvidia-smi
Wed Jan 17 10:21:32 2026
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 550.54.14 Driver Version: 550.54.14 CUDA Version: 12.4 |
|-------------------------------+----------------------+----------------------+
| GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. |
| | | MIG M. |
|===============================+======================+======================|
| 0 NVIDIA A100-SXM4-40GB On| 00000000:81:00.0 Off | 0 |
| N/A 46C P0 165W / 400W | 8200MiB / 40960MiB | 72% Default |
| | | Enabled |
+-------------------------------+----------------------+----------------------+
Qué significa: Está confirmando la rama exacta del controlador, compatibilidad CUDA, persistence mode y si MIG está habilitado.
Decisión: Fije este conjunto (modelo GPU + versión del controlador + versión CUDA) en su CMDB y en manifiestos de despliegue. Si cambia inesperadamente, trátelo como un cambio de producción.
Tarea 2: Revisar instancias MIG y confirmar que no haya compartición accidental
cr0x@server:~$ nvidia-smi -L
GPU 0: NVIDIA A100-SXM4-40GB (UUID: GPU-aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee)
MIG 1g.5gb Device 0: (UUID: MIG-GPU-aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/1/0)
MIG 1g.5gb Device 1: (UUID: MIG-GPU-aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/2/0)
MIG 2g.10gb Device 2: (UUID: MIG-GPU-aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/3/0)
Qué significa: La GPU está particionada. Las cargas pueden asignarse a UUIDs de dispositivos MIG.
Decisión: Si hace scheduling multi-inquilino, programe inquilinos solo en instancias MIG dedicadas. Si no puede explicar qué se comparte entre instancias para su arquitectura, no afirme «aislamiento fuerte».
Tarea 3: Confirmar qué procesos están en la GPU
cr0x@server:~$ nvidia-smi pmon -c 1
# gpu pid type sm mem enc dec jpg ofa command
0 19423 C 78 20 0 0 0 0 python
0 20110 C 5 2 0 0 0 0 tritonserver
Qué significa: Ve procesos de cómputo activos y uso aproximado de recursos.
Decisión: Si espera comportamiento de inquilino único y ve procesos desconocidos, deténgase e investigue. Si es multi-inquilino, verifique que los procesos correspondan a pods/trabajos esperados.
Tarea 4: Mapear archivos de dispositivo GPU y permisos (superficie de escape de contenedor)
cr0x@server:~$ ls -l /dev/nvidia* /dev/dri/*
crw-rw-rw- 1 root root 195, 0 Jan 17 10:15 /dev/nvidia0
crw-rw-rw- 1 root root 195, 255 Jan 17 10:15 /dev/nvidiactl
crw-rw-rw- 1 root root 195, 254 Jan 17 10:15 /dev/nvidia-modeset
crw-rw---- 1 root video 226, 0 Jan 17 10:15 /dev/dri/card0
crw-rw---- 1 root render 226, 128 Jan 17 10:15 /dev/dri/renderD128
Qué significa: Nodos de dispositivo GPU con permisos para todos son una señal de alerta. Amplían quién puede hablar con el driver del kernel.
Decisión: Endurezca los permisos (grupos como video/render) y asegure que los contenedores solo reciban los dispositivos específicos que necesitan. «chmod 666» pertenece a laboratorios, no a producción.
Tarea 5: Verificar que IOMMU esté habilitado (contención de DMA)
cr0x@server:~$ dmesg | grep -E "IOMMU|DMAR" | head
[ 0.812345] DMAR: IOMMU enabled
[ 0.812900] DMAR: Host address width 46
[ 0.813210] DMAR: DRHD base: 0x000000fed90000 flags: 0x0
Qué significa: La plataforma tiene remapeo DMA activado. Este es un control fundamental contra «el dispositivo puede leer todo».
Decisión: Si no ve esto, corrija parámetros de arranque (Intel: intel_iommu=on; AMD: amd_iommu=on) y valide en staging. No tener IOMMU + cargas no confiables es un reto voluntario.
Tarea 6: Confirmar que la GPU esté en un grupo IOMMU (sanidad de passthrough)
cr0x@server:~$ for d in /sys/kernel/iommu_groups/*/devices/*; do echo "$(basename "$(dirname "$d")") $(basename "$d")"; done | grep -i nvidia | head
27 0000:81:00.0
27 0000:81:00.1
Qué significa: La GPU y sus funciones asociadas están agrupadas para aislamiento.
Decisión: Si su GPU comparte un grupo IOMMU con dispositivos aleatorios, el passthrough y el aislamiento fuerte se complican. Ajuste BIOS/ACS o elija ranuras/plataformas diferentes.
Tarea 7: Revisar taint del driver del kernel y versiones de módulo
cr0x@server:~$ uname -r
6.5.0-27-generic
cr0x@server:~$ modinfo nvidia | egrep "version:|srcversion|vermagic"
version: 550.54.14
srcversion: 1A2B3C4D5E6F7890ABCD123
vermagic: 6.5.0-27-generic SMP preempt mod_unload
Qué significa: Confirma la build exacta del módulo del kernel y la compatibilidad del kernel. Útil durante la investigación de incidentes («¿es este el nodo con el controlador raro?»).
Decisión: Si tiene versiones mezcladas de controladores en el mismo pool, deje de hacerlo. Convierte la depuración en arqueología.
Tarea 8: Vigilar errores Xid de GPU (señales de fallo hardware/driver)
cr0x@server:~$ journalctl -k -g "NVRM: Xid" -n 5
Jan 17 09:58:01 server kernel: NVRM: Xid (PCI:0000:81:00): 31, pid=19423, name=python, Ch 0000003a
Jan 17 09:58:01 server kernel: NVRM: Xid (PCI:0000:81:00): 13, Graphics Exception: ESR 0x404600=0x80000002
Qué significa: Los códigos Xid indican fallos de GPU. Algunos son bugs de aplicación; otros son regresiones del driver; otros son hardware.
Decisión: Si los Xid se correlacionan con una actualización del driver, rollback canary. Si se correlacionan con cargas específicas, aislar y reproducir. Si se correlacionan con temperatura/potencia, revise refrigeración y alimentación.
Tarea 9: Comprobar salud PCIe (errores correctables pueden señalar inestabilidad)
cr0x@server:~$ journalctl -k -g "PCIe Bus Error" -n 5
Jan 17 09:57:49 server kernel: pcieport 0000:80:01.0: PCIe Bus Error: severity=Corrected, type=Physical Layer
Jan 17 09:57:49 server kernel: pcieport 0000:80:01.0: device [8086:2030] error status/mask=00000001/00002000
Qué significa: Errores correctables no son «están bien». Son un indicador de enlaces inestables, risers defectuosos, integridad de señal marginal o problemas de potencia.
Decisión: Si los conteos aumentan, programe mantenimiento antes de sufrir errores no corregibles y entrenamientos muertos. La fiabilidad es la prima aburrida de la seguridad.
Tarea 10: Validar aislamiento de dispositivos por cgroup en un nodo Kubernetes
cr0x@server:~$ kubectl get pods -A -o wide | grep gpu
mlteam-a infer-7d9c6f6d7d-9p2kq 1/1 Running 0 2d 10.42.3.19 gpu-node-03
mlteam-b train-0 1/1 Running 0 1d 10.42.3.20 gpu-node-03
cr0x@server:~$ kubectl exec -n mlteam-a infer-7d9c6f6d7d-9p2kq -- ls -l /dev/nvidia0
crw-rw---- 1 root video 195, 0 Jan 17 10:15 /dev/nvidia0
Qué significa: Dos pods comparten un nodo; está comprobando si la exposición de dispositivos está controlada y no es world-writable.
Decisión: Si hace multi-inquilino, aplique node pools + taints/tolerations + políticas del device plugin para que inquilinos no relacionados no coexistan a menos que acepte explícitamente ese riesgo.
Tarea 11: Confirmar si el reset de GPU es posible y si se usa entre inquilinos
cr0x@server:~$ nvidia-smi --gpu-reset -i 0
GPU 00000000:81:00.0 is currently in use by one or more processes.
Reset could not be performed.
Qué significa: No puede resetear una GPU en uso; los resets son disruptivos y requieren orquestación.
Decisión: Si confía en resets como «borrado», cree un hook en el scheduler: drenar cargas, resetear y luego admitir al siguiente inquilino. De lo contrario, trate «reset entre inquilinos» como un control fantasioso.
Tarea 12: Revisar persistence mode y decidir si perjudica el aislamiento
cr0x@server:~$ nvidia-smi -q | grep -A2 "Persistence Mode"
Persistence Mode : Enabled
Accounting Mode : Disabled
Qué significa: Persistence mode mantiene el estado del driver caliente para arranques más rápidos. También puede mantener más estado entre límites de trabajo.
Decisión: Para aislamiento estricto multi-inquilino, considere desactivar persistence mode en pools compartidos y medir la penalización de rendimiento. No lo haga a ciegas; hágalo intencionalmente.
Tarea 13: Inspeccionar hugepages y presión de memoria fijada (rendimiento + efectos secundarios)
cr0x@server:~$ grep -E "HugePages|Hugetlb" /proc/meminfo
HugePages_Total: 8192
HugePages_Free: 1024
HugePages_Rsvd: 512
Hugetlb: 16777216 kB
Qué significa: Las cargas GPU suelen usar memoria fijada y hugepages indirectamente. La presión aquí puede causar picos de latencia y fallos extraños que parecen «la GPU está lenta».
Decisión: Si HugePages_Free colapsa durante el inicio de un trabajo, ajuste las asignaciones de hugepages por pool de nodos y deje de sobreaprovisionar memoria como si fuera un hobby.
Tarea 14: Detectar mapeos sospechosos de dispositivos dentro de un contenedor
cr0x@server:~$ kubectl exec -n mlteam-b train-0 -- sh -lc 'mount | grep -E "nvidia|dri" || true; ls -l /dev | grep -E "nvidia|dri"'
tmpfs on /dev type tmpfs (rw,nosuid,strictatime,mode=755,size=65536k)
crw-rw---- 1 root video 195, 0 Jan 17 10:15 nvidia0
crw-rw---- 1 root video 195, 255 Jan 17 10:15 nvidiactl
Qué significa: Está comprobando si el contenedor ve más nodos de dispositivo de los previstos. Algunos runtimes montan controles extra por accidente.
Decisión: Si los contenedores ven /dev/nvidiactl y no lo esperaba, revise la configuración del runtime. Minimice la exposición de dispositivos. La superficie de ataque escala con los descriptores de archivo.
Tarea 15: Confirmar estado de kernel lockdown / Secure Boot (previene cierta manipulación del kernel)
cr0x@server:~$ cat /sys/kernel/security/lockdown
integrity
cr0x@server:~$ mokutil --sb-state
SecureBoot enabled
Qué significa: Lockdown y Secure Boot dificultan cargar módulos de kernel sin firmar o manipular el kernel—útil cuando su driver GPU es un blob privilegiado.
Decisión: Si Secure Boot está apagado en entornos donde ejecuta cargas no confiables, está aceptando un radio de explosión mayor. Enciéndalo y gestione la firma de controladores correctamente.
Tarea 16: Ver qué le hace el scheduler (¿está co-ubicando inquilinos?)
cr0x@server:~$ kubectl describe node gpu-node-03 | egrep -A3 "Taints|Labels"
Labels: nodepool=gpu-shared
accelerator=nvidia
Taints: dedicated=gpu-shared:NoSchedule
Qué significa: Las etiquetas/taints del nodo indican si el clúster está pensado para compartir.
Decisión: Si cargas sensibles aterrizan en gpu-shared, eso es una falla de política. Arregle restricciones de scheduling y controles de admisión, no solo «diga a la gente que tenga cuidado».
Eso es más de una docena de comprobaciones. Ejecútelas rutinariamente. Automatice las que pueda y alerte sobre desvíos. La seguridad GPU es 30% arquitectura y 70% no dejar que la flota cambie silenciosamente bajo usted.
Manual de diagnóstico rápido
Cuando algo huele mal—salidas inesperadas, latencia inexplicada, correlaciones raras entre inquilinos—necesita una vía rápida para «¿es esto un cuello de botella, un bug o una violación de límites?»
Aquí hay un playbook que funciona en medio de un incidente.
Primero: clasifique la falla (confidencialidad vs integridad vs disponibilidad)
- Confidencialidad: prompts, embeddings, tensores o pesos aparecen donde no deberían; logs muestran accesos inesperados; inquilinos reportan «ven a otros».
- Integridad: resultados derivan, salidas no deterministas, caídas silenciosas de precisión, checksums de artefactos que no coinciden.
- Disponibilidad: cuelgues de GPU, resets, tormentas Xid, caídas de rendimiento, timeouts.
Segundo: determine si está ocurriendo compartición
- ¿Está MIG habilitado y correctamente asignado, o está haciendo time-slicing de GPUs completas?
- ¿Hay dos inquilinos en el mismo nodo físico? ¿La misma GPU? ¿Back-to-back en la misma GPU?
- ¿Mantiene persistence mode los contextos calientes?
Tercero: busque las «señales clásicas»
- Logs del kernel: errores Xid, errores de bus PCIe, fallos de IOMMU.
- Mapeo de procesos: PIDs inesperados en la GPU, contextos zombis.
- Desviación del scheduler: taints/labels cambiados, mala configuración de pools, nueva versión del plugin GPU.
Cuarto: aislar por sustracción
- Mueva la carga a un nodo conocido de inquilino único y compare el comportamiento.
- Desactive la optimización «útil»: persistence mode, pools de memoria agresivos, time-slicing.
- Fije versiones de driver/runtime y reproduzca. Si no puede reproducir de forma determinista, no puede decir que lo arregló.
Quinto: decida si está en «modo incidente de seguridad»
Si hay exposición creíble de datos entre inquilinos, deje de tratarlo como un bug de rendimiento. Congele cambios de scheduling, preserve logs, snapshotee configuraciones y escale.
Aquí quiere la idea parafraseada de Gene Kranz: sea duro y competente—sin drama, sin negación, solo respuesta disciplinada.
Errores comunes: síntomas → causa raíz → solución
Las fallas de seguridad en GPU a menudo se hacen pasar por «rendimiento raro» o «ML no determinista». Algunas lo son. Otras no. Aquí tiene una guía de campo.
Error 1: «Estamos seguros porque es un contenedor»
Síntomas: un pod puede ver nodos de dispositivo GPU que no debería; crashes de kernel inesperados; el equipo de seguridad pregunta «¿qué módulo del kernel parsea entradas de inquilinos?» y todos miran al suelo.
Causa raíz: el acceso a GPU conecta directamente con drivers del kernel del host. Los contenedores no virtualizan el kernel.
Solución: restrinja la exposición de /dev, use node pools dedicados para inquilinos no confiables y trate las actualizaciones del driver GPU como actualizaciones de kernel—con canaries y rollbacks.
Error 2: «No necesitamos IOMMU; es más lento»
Síntomas: corrupción de memoria inexplicada, panics raros en el host, hallazgos de auditoría alarmantes o incapacidad para defender límites DMA.
Causa raíz: remapeo DMA deshabilitado. La GPU puede acceder a memoria del host con demasiada libertad.
Solución: habilite IOMMU en BIOS y parámetros del kernel; valide el agrupamiento de dispositivos; mida el impacto real en lugar de asumir que es catastrófico.
Error 3: «Resetear la GPU equivale a borrado seguro»
Síntomas: «reseteamos entre inquilinos» pero en realidad no puede resetear bajo carga; fallos intermitentes después de resets forzados; persistencia de comportamiento de contexto obsoleto.
Causa raíz: los resets son operativamente difíciles; algún estado puede persistir en otros lugares; y no puede resetear lo que no puede drenar.
Solución: implemente drenado de trabajos + orquestación de resets, o cambie a aislamiento fuerte (GPUs dedicadas/instancias MIG) y cero explícito de buffers en el código.
Error 4: «El modo de rendimiento es inofensivo»
Síntomas: aumento de correlación entre trabajos, comportamiento extraño de warm-start y deriva que desaparece al reiniciar nodos.
Causa raíz: persistence mode, asignadores de caché y contextos calientes mantienen más estado del que imagina.
Solución: defina niveles de seguridad. Para cargas de alta sensibilidad, desactive funciones de estado caliente o aísle en hardware de un solo inquilino.
Error 5: «MIG significa aislamiento perfecto»
Síntomas: los inquilinos todavía se influyen en el rendimiento; los auditores preguntan qué se comparte; no puede responder sin un slide del proveedor.
Causa raíz: MIG reduce la compartición pero no la borra. Algunos componentes permanecen compartidos y el firmware es una capa común.
Solución: trate MIG como herramienta de reducción de riesgo, no como prueba absoluta. Añada políticas de scheduling, monitoreo y límites sobre qué inquilinos pueden cohabitar.
Error 6: «Es solo no determinismo»
Síntomas: salidas reguladas o críticas para el negocio derivan; ejecuciones diferentes producen decisiones distintas; ocurre solo bajo contención.
Causa raíz: la contención de recursos compartidos cambia el orden de ejecución, la temporización y el comportamiento de reducciones en punto flotante.
Solución: habilite modos deterministas donde estén disponibles, aísle cargas críticas y deje de mezclar trabajos ad-hoc con pipelines regulados en GPUs compartidas.
Error 7: «Parchearemos luego; las GPUs son frágiles»
Síntomas: ramas de controladores divergen; teme las actualizaciones; se acumulan advisories de seguridad; al final queda anclado a un stack antiguo que no puede ejecutar nuevos frameworks.
Causa raíz: falta de disciplina de canary y rollback, más cobertura de pruebas insuficiente para cargas GPU.
Solución: construya una pipeline de parches GPU con smoke tests automatizados (kernels simples, patrones de asignación de memoria, colectivos NCCL) y despliegues escalonados.
Chiste #2 (breve, relevante): «Parchearemos el driver GPU el próximo trimestre» es la versión de infraestructura de «empezaré las copias de seguridad mañana».
Listas de verificación / plan paso a paso
Paso a paso: endurecer un pool de nodos GPU multi-inquilino
- Decida su nivel de seguridad: nodos de inquilino único para cargas sensibles; nodos compartidos solo para cargas internas de confianza o para inquilinos que acepten controles más fuertes.
- Habilite IOMMU y verifíquelo en logs. Confirme grupos IOMMU sensatos. Esto es básico para la seguridad DMA.
- Estandarice la matriz driver/runtime por pool. Un pool, una rama de driver, un objetivo CUDA/ROCm. El desvío es donde se esconden los incidentes.
- Bloquee permisos de dispositivo en /dev/nvidia* y /dev/dri/*. Asegure que los contenedores reciban solo los dispositivos que necesitan.
- Use particionado deliberadamente: perfiles MIG para compartición controlada; evite time-slicing ad-hoc entre inquilinos no relacionados.
- Implemente controles de admisión para que solo namespaces aprobados puedan solicitar GPUs y solo en pools aprobados (mediante node selectors, taints y runtime class).
- Desactive características «útiles» de persistencia para pools de alta sensibilidad, o demuestre que no retienen estado sensible en su entorno.
- Haga cero de buffers sensibles en el código de la aplicación en rutas de error y salidas tempranas. No confíe en el comportamiento del asignador.
- Instrumente logs del kernel para Xid, fallos de IOMMU y errores PCIe. Alarme por cambios, no solo por conteos absolutos.
- Canarye cada actualización de driver con cargas representativas y luego despliegue gradualmente. Trate los nodos GPU como una flota de kernel especial—porque lo son.
Checklist: señales para dejar de compartir GPUs ahora mismo
- No puede garantizar qué inquilino corrió antes que otro en la misma GPU.
- No tiene IOMMU habilitado y verificado.
- Los nodos de dispositivo GPU son world-writable o ampliamente expuestos a pods.
- No puede mapear PIDs de GPU a pods/trabajos rápidamente durante la respuesta a incidentes.
- No tiene pipeline canary para actualizaciones de controladores y teme parchear.
- Maneja datos regulados o secretos contractuales y su historia de aislamiento es «confíe en nosotros».
Checklist: telemetría mínima para seguridad y fiabilidad de GPU
- Versión del driver, versión de firmware (donde esté disponible) y versión del kernel por nodo.
- Utilización de GPU, uso de memoria, eventos ECC y eventos de reset.
- Logs del kernel: eventos Xid, fallos de IOMMU, errores PCIe.
- Logs de colocación del scheduler: inquilino → nodo → GPU/instancia MIG.
- Ciclo de vida del trabajo: tiempos de inicio/parada, clasificación del modo de fallo y si la GPU fue drenada/resetada entre inquilinos.
Preguntas frecuentes
1) ¿Ya existe un equivalente de «Spectre para GPUs»?
Ha habido problemas de canales laterales y de aislamiento en GPUs en investigación y advisories, pero el punto más amplio es estructural: las GPUs comparten recursos y ejecutan drivers privilegiados.
Las condiciones para una ruptura de clase mayor existen incluso si el CVE titular no aparece.
2) ¿Son prácticos los canales laterales en el mundo real?
Si el atacante puede ejecutar código en la misma GPU física (o en el mismo host con rutas compartidas), la practicidad aumenta mucho.
La parte más difícil suele ser la co-ubicación; el scheduling en la nube y los clústeres compartidos facilitan eso más de lo que nos gusta admitir.
3) ¿MIG resuelve la seguridad multi-inquilino?
Ayuda—significativamente—al particionar recursos. Pero «resuelve» es demasiado fuerte.
Aún tiene firmware, drivers y algunas rutas de hardware compartidas. Trate MIG como «reducción de riesgo + mejores primitivas de scheduling», no como una brecha de aire mágica.
4) ¿Cuál es el mayor riesgo de seguridad de GPU en Kubernetes?
El límite es el driver del kernel del host. Si le da a un pod acceso a la GPU, le está dando una superficie de ataque compleja en el kernel.
El otro riesgo común es la deriva de políticas: pods aterrizando en nodos compartidos porque las etiquetas/taints no se aplicaron.
5) ¿Deberíamos desactivar persistence mode?
Para pools multi-inquilino de alta sensibilidad, desactivarlo es un valor por defecto razonable—luego mida el impacto en el arranque y compense con planificación de capacidad.
Para nodos de inquilino único, persistence mode suele estar bien y mejora la fiabilidad al reducir la rotación del driver.
6) ¿Cómo prevenimos filtraciones por memoria GPU residual?
No confíe en «probablemente se limpia». Añada cero explícito para buffers sensibles en el código de la aplicación, especialmente en rutas de error.
Operativamente, aisle inquilinos (GPU dedicada o instancia MIG) y considere orquestación de drenado/reset donde sea factible.
7) ¿Las actualizaciones de drivers GPU son sobre todo un problema de seguridad o de fiabilidad?
Ambos. El driver es código privilegiado. Los advisories de seguridad importan.
Pero en la práctica, la mayoría de los equipos sufren primero regresiones y cuelgues. Construya una pipeline canary para poder parchear sin apostar.
8) ¿La computación confidencial puede proteger cargas GPU?
La computación confidencial en CPU ayuda a proteger memoria del host y límites de VM, lo cual es valioso.
Las GPUs añaden complejidad: DMA de dispositivo, cachés compartidas y modelos de confianza específicos del proveedor. Trátelo como «mejora la historia» más que «lo resuelve».
9) ¿Cuál es la reducción de riesgo más rápida si no podemos rediseñar todo?
Deje de co-ubicar inquilinos no relacionados en la misma GPU física. Use GPUs dedicadas o instancias MIG con scheduling estricto.
Luego habilite IOMMU y bloquee el acceso a dispositivos. Esos dos cambios eliminan muchos modos de fallo tontos.
10) ¿Qué deberíamos decir a auditores y clientes?
Dígales lo que realmente hace: si las GPUs son dedicadas, particionadas o time-sliced; cómo controla el acceso a dispositivos; su cadencia de parches; y su plan de respuesta a incidentes.
No sobrevenda «aislamiento» a menos que lo pueda explicar hasta el nivel de dispositivo y driver.
Próximos pasos que puede hacer esta semana
Si quiere un único takeaway accionable: deje de tratar las GPUs como «solo aceleradores». Son ordenadores compartidos con una jerarquía de memoria extraña y un driver privilegiado del tamaño de una pequeña ciudad.
- Inventaríe y fije sus versiones GPU/driver/runtime por pool de nodos. Haga visible la deriva.
- Habilite y verifique IOMMU. Luego confirme agrupamiento IOMMU sensato.
- Audite permisos en /dev y la exposición de dispositivos en contenedores. Elimine accesos amplios.
- Decida su política de co-ubicación: inquilino único, solo MIG o time-sliced (último recurso).
- Añada una pipeline canary para actualizaciones de controladores GPU con criterios de rollback.
- Instrumente las señales: errores Xid, errores PCIe, fallos IOMMU y el mapeo de colocación del scheduler.
Si mañana ocurre un «Spectre para gráficos», no ganará con el mejor comunicado de prensa.
Ganará teniendo menos límites compartidos, mejor telemetría y la disciplina para desplegar mitigaciones sin llevarse la producción por delante.