Ciberseguridad

CVE-2026-27940: Desbordamiento de Enteros en llama.cpp Elude Parche Previo del Heap

Team Nippysoft
10 min de lectura
CVE-2026-27940: Desbordamiento de Enteros en llama.cpp Elude Parche Previo del Heap

Se ha divulgado una vulnerabilidad crítica de desbordamiento de enteros en llama.cpp, el motor de inferencia LLM de código abierto más utilizado, bajo el identificador CVE-2026-27940. El fallo en el parser de archivos GGUF permite a atacantes crear archivos de modelo maliciosos que desencadenan un desbordamiento de buffer en heap, con potencial para lograr ejecución remota de código. Con una puntuación CVSS de 7.8 (Alta) e impacto total en confidencialidad, integridad y disponibilidad, esta vulnerabilidad es especialmente significativa porque elude CVE-2025-53630, un parche aplicado a la misma función para corregir un problema similar. Los mantenedores de ggml-org han publicado la corrección en la compilación b8146. Todas las versiones anteriores están afectadas. La vulnerabilidad fue reportada por el investigador @adi0x90 y está clasificada bajo CWE-122 y CWE-190.

La Vulnerabilidad y Sus Orígenes

CVE-2026-27940 apunta a la función gguf_init_from_file_impl() en ggml/src/gguf.cpp, el parser principal responsable de leer archivos de modelo GGUF. Durante la inicialización, la función itera sobre los metadatos de los tensores para calcular el tamaño total del buffer necesario. Ese tamaño acumulado se almacena en ctx->size, una variable de tipo size_t.

La vulnerabilidad predecesora, CVE-2025-53630, abordó un desbordamiento de enteros en este mismo bucle de acumulación. El parche agregó verificaciones para evitar que ctx->size desbordara al sumar los tamaños individuales de cada tensor. Sin embargo, esta corrección fue incompleta. No protegió el cálculo final de mem_size que ocurre después del bucle en la línea ~665, donde ctx->size se combina con el overhead de los tensores para determinar el tamaño total de asignación. Esta brecha entre la ruta de código parcheada y el cálculo desprotegido creó la apertura exacta que CVE-2026-27940 explota.

Mecánica del Desbordamiento de Enteros

El ataque construye un archivo GGUF que contiene dos tensores I8, cada uno con un valor de dimensión (ne[0]) establecido en 0x7FFFFFFFFFFFFFC0. Cada tensor pasa individualmente la verificación de desbordamiento del parche de CVE-2025-53630 porque la capacidad restante antes de SIZE_MAX es suficiente para cualquiera de ellos por separado. Combinados, sin embargo, los dos valores producen ctx->size = 0xFFFFFFFFFFFFFF80, equivalente a SIZE_MAX - 127.

El fallo crítico ocurre en el cálculo final del tamaño de memoria:

const size_t mem_size = (n_tensors + 1) * ggml_tensor_overhead() + ctx->size;

Cuando el overhead de los tensores (1.104 bytes) se suma a SIZE_MAX - 127, el resultado desborda módulo 264 a aproximadamente 976 bytes. El asignador de memoria reserva solo 976 bytes en lugar del buffer de escala de exabytes que los datos reales del tensor requieren. Este es el núcleo de la vulnerabilidad: una operación aritmética aparentemente válida que silenciosamente produce una asignación catastróficamente pequeña.

Desbordamiento de Enteros: Envolvente SIZE_MAX SIZE_MAX (2^64 - 1) Tensor 1: 0x7FFFFFFFFFFFFFC0 Tensor 2: 0x7FFFFFFFFFFFFFC0 [OK] Verificacion individual [OK] Verificacion individual ctx->size = 0xFFFFFFFFFFFFFF80 (SIZE_MAX - 127) + ggml_tensor_overhead() = 1.104 bytes DESBORDAMIENTO: Envolvente mod 2^64 Buffer asignado: 976 bytes asignados fread() escribe 528+ bytes fuera del limite CORRUPCION DE HEAP bypass tcache → secuestro de punteros → RCE

De la Corrupción de Heap a la Ejecución de Código

Con el buffer insuficiente de 976 bytes asignado, la región de datos disponible para el contenido del tensor es de solo 608 bytes. La llamada posterior a fread() intenta leer los datos del tensor suministrados por el atacante en este espacio. Un atacante que proporciona 1.136 o más bytes de datos controlados escribe al menos 528 bytes más allá del límite asignado, corrompiendo metadatos y estructuras adyacentes del heap.

El aviso de seguridad demuestra una cadena completa de explotación desde el fallo inicial hasta la ejecución remota de código. Al ajustar las dimensiones de los tensores para producir asignaciones dentro del rango de tcache de glibc (tamaño de chunk de 992 bytes), la memoria corrupta elude las verificaciones de integridad del heap durante free(). El path rápido de tcache coloca silenciosamente el chunk corrupto en la lista libre. Las llamadas posteriores a malloc() retornan memoria pre-llenada por el atacante, permitiendo el secuestro de punteros a funciones. Se han logrado exploits de prueba de concepto con acceso root en macOS ARM64 y Ubuntu 24.04.

CVE-2025-53630 vs CVE-2026-27940

Atributo CVE-2025-53630 CVE-2026-27940
Causa Raíz Desbordamiento de enteros en el bucle de acumulación de tamaños Desbordamiento de enteros en el cálculo final de mem_size
Ubicación Línea ~642, dentro del bucle Línea ~665, después del bucle
CVSS Alto 7.8 (Alto)
CWE CWE-122, CWE-680 CWE-122, CWE-190
Explotabilidad Lectura/escritura OOB por offset mal calculado Desbordamiento de heap por asignación insuficiente + fread
RCE Demostrada No públicamente Sí, con bypass de tcache
Corrección Verificaciones en el bucle de acumulación Verificaciones en mem_size final (compilación b8146)

Este patrón de corrección incompleta que es eludida destaca un error común en ingeniería de seguridad: parchear solo la ruta de código identificada sin auditar los cálculos adyacentes que consumen los mismos datos influenciados por el atacante. Una corrección integral requiere verificar cada operación aritmética sobre entradas no confiables, no solo la reportada inicialmente.

Componentes Afectados

La vulnerabilidad se activa en cualquier ruta de código que llame a gguf_init_from_file() con no_alloc=false:

  • llama-quantize — herramienta de cuantización de modelos (tools/quantize/quantize.cpp)
  • llama-imatrix — cálculo de matrices de importancia (tools/imatrix/imatrix.cpp)
  • Carga de vectores de control — mediante common/common.cpp
  • llama-gguf — utilidad de inspección de archivos GGUF (examples/gguf/gguf.cpp)

De forma crítica, la ruta principal de carga de modelos utilizada durante la inferencia opera con no_alloc=true y no está afectada. Las cargas de trabajo de inferencia estándar son seguras. Sin embargo, cualquier flujo que involucre conversión, cuantización o inspección de archivos GGUF no confiables está en riesgo. Considere un desarrollador que descarga un modelo GGUF de un repositorio público y ejecuta llama-quantize sobre él — esta operación rutinaria se convierte en el vector de ataque en un escenario de cadena de suministro.

Implicaciones para el Ecosistema de IA

llama.cpp se ha convertido en un componente fundamental del stack de IA de código abierto, impulsando la inferencia local para proyectos que van desde herramientas individuales de desarrolladores hasta plataformas de despliegue empresarial. Los archivos de modelo se comparten rutinariamente a través de repositorios como Hugging Face, y la confianza implícita depositada en GGUF como un contenedor pasivo de datos convierte los ataques a la cadena de suministro mediante modelos maliciosos en un vector de amenaza realista.

Esta vulnerabilidad subraya la fragilidad de la seguridad aritmética en bases de código C/C++ que procesan entradas no confiables. Que una vulnerabilidad parcheada fuera eludida apuntando a una ruta de código no verificada a pocas líneas de la corrección original plantea interrogantes sobre la completitud de las mitigaciones en la biblioteca ggml.

Remediación y Recomendaciones

El equipo de ggml-org ha corregido CVE-2026-27940 en la compilación b8146. Los equipos que ejecuten cualquier versión anterior deben actualizar inmediatamente. Más allá de la actualización, se recomiendan las siguientes medidas defensivas:

  • Verificar la procedencia de archivos de modelo — Cargar solo archivos GGUF de fuentes confiables. Implementar verificación de hash para modelos descargados de repositorios públicos.
  • Aislar herramientas de procesamiento — Ejecutar las utilidades de cuantización, conversión e inspección en entornos aislados (contenedores, máquinas virtuales) con privilegios mínimos.
  • Monitorear archivos GGUF anómalos — Archivos con valores de dimensiones de tensor inusualmente grandes o tamaños declarados discrepantes deben activar alertas en pipelines automatizados de modelos.
  • Auditar integraciones personalizadas — Si su aplicación llama directamente a gguf_init_from_file() con no_alloc=false, asegúrese de utilizar la versión parcheada de ggml.

Los detalles técnicos completos y materiales de prueba de concepto están disponibles en el Aviso de Seguridad de GitHub GHSA-3p4r-fq3f-q74v.

Suscríbete

Recibe los últimos artículos directamente en tu bandeja de entrada.

Este sitio está protegido por reCAPTCHA. Aplican la Política de Privacidad y los Términos de Servicio de Google.

Comentarios

Aún no hay comentarios. ¡Sé el primero en compartir tu opinión!

¡Suscrito!

¡Registrado! Hemos enviado un enlace de confirmación a tu correo electrónico. Si no lo ves, revisa tu carpeta de spam.

Error

Ocurrió un error. Por favor intenta de nuevo.