Reports
MEDIA[CORRUPCIÓN DE MEMORIA]#3910393

Desbordamiento de pila en el motor CONNECT de MariaDB al leer columnas DOUBLE de tablas DOS

En el motor CONNECT de MariaDB, leer una columna DOUBLE ancha de una tabla TABLE_TYPE=DOS escribía un byte nulo fuera de un búfer de pila de 64 bytes, lo que permitía tumbar el servidor.

Resumen
Resumen en castellano de un reporte público, no una traducción literal. El código y los comandos se mantienen como en el original.

Resumen

El fallo está en el motor de almacenamiento CONNECT de MariaDB, concretamente en la función TYPVAL<double>::SetValue_char() del fichero storage/connect/value.cpp. Esta función convierte a número el texto de un campo DOUBLE y, para ello, lo copia antes a un búfer local de 64 bytes en la pila.

La copia en sí está bien acotada: nunca pasa de 31 bytes. El problema es la línea siguiente, la que coloca el terminador de cadena. En lugar de usar la longitud realmente copiada, usa n, que es el ancho declarado del campo en SQL:

bool TYPVAL<double>::SetValue_char(const char *p, int n){
  if (p && n > 0) {
    char buf[64];

    for (; n > 0 && *p == ' '; p++)
      n--;

    memcpy(buf, p, MY_MIN(n, 31));
    buf[n] = '\0';

Como SQL admite anchos de hasta 255, una columna DOUBLE(255,30) hace que se ejecute buf[255] = '\0' sobre un búfer de 64 posiciones: un byte 0x00 escrito hasta 191 bytes más allá del final del búfer, según el investigador. El caso tiene asignado el CVE-2026-107815.

Cómo llega el ancho declarado hasta ahí

El investigador siguió el valor desde la definición de la tabla hasta la línea vulnerable, y en ningún punto se recorta:

  1. La capa SQL acepta DOUBLE(255,30) y fija field_length a 255 (sql/field.cc).
  2. CONNECT copia ese ancho tal cual (ha_connect.cc).
  3. El ancho pasa a ser el campo Long de la columna, también sin cambios (reldef.cpp, colblk.cpp, tabdos.cpp).
  4. DOSCOL::ReadColumn() asigna field = Long y lo pasa directamente al parser del valor (tabdos.cpp):
        case TYPE_DOUBLE:
          if (!(err = Value->SetValue_char(p, field))) {

Pasos de reproducción

El reporte no incluye el SQL ni el fichero DOS del PoC en el propio texto: están en dos gists que aportó el investigador.

  1. Compilar MariaDB con AddressSanitizer (ASAN). Dockerfile del investigador: https://gist.github.com/dldLambda/58ad85abfb9bc65d661a69faba7523e0
  2. Ejecutar su script PoC.sh, que lleva en sus parámetros de arranque tanto el disparador como la configuración: https://gist.github.com/dldLambda/f4bc2a9c343bb28404989dba2628d2bf
  3. Lo que dispara el fallo es leer de vuelta una columna DOUBLE(M,D) con un ancho grande (por ejemplo DOUBLE(255,30)) de una tabla CONNECT con TABLE_TYPE='DOS'.
  4. Con ASAN, el servidor informa de un stack-buffer-overflow de escritura de 1 byte en la línea buf[n] = '\0' de TYPVAL<double>::SetValue_char. Sin ASAN, el servidor se cae.

Impacto

Un atacante que pueda provocar esa lectura consigue tumbar el servidor MariaDB, es decir, una denegación de servicio. El reporte solo describe este impacto (caída del servidor); no plantea ejecución de código ni detalla qué privilegios hacen falta para crear la tabla CONNECT.

Qué aprender de este caso

  • Cuando una función acota la copia con MIN(n, límite), revisa todas las líneas siguientes que usan n: aquí el memcpy estaba bien limitado, pero el terminador buf[n] = '\0' usaba la longitud sin recortar. Lo correcto es guardar la longitud acotada en una variable y usar solo esa.
  • En código que convierte texto a número con un búfer fijo en pila, busca de dónde sale la longitud: si viene de metadatos que controla el usuario (como el ancho declarado de una columna SQL), trátala como entrada no confiable aunque haya atravesado varias capas internas.
  • Los motores de almacenamiento que leen ficheros externos (como CONNECT con tablas DOS) son buen objetivo para fuzzing: combinar anchos de columna extremos, que la capa SQL acepta, con compilación bajo ASAN destapa escrituras de un solo byte que sin sanitizador pasarían desapercibidas o solo causarían caídas difíciles de diagnosticar.