Resumen
MariaDB expone la función ST_GeomFromGeoJSON() para convertir texto GeoJSON en geometrías espaciales. El investigador encontró que el analizador de GeoJSON no impone ningún límite a la recursión cuando una GeometryCollection contiene a su vez otra GeometryCollection. Un usuario autenticado con solo el privilegio SELECT podía enviar un documento GeoJSON suficientemente anidado para agotar la pila del hilo y provocar un SIGSEGV, tirando abajo el proceso mysqld completo.
Como MariaDB usa una arquitectura de un solo proceso con múltiples hilos, el fallo no afecta a una única conexión: mata a todo el servidor. Todas las sesiones activas se pierden, las transacciones sin confirmar se revierten y hace falta reiniciar el servicio.
La raíz del problema es una recursión sin acotar en el analizador de GeoJSON de sql/spatial.cc, sin ninguna comprobación de desbordamiento de pila, cuando las rutas equivalentes del código sí la tienen: las funciones JSON de sql/item_jsonfunc.cc incluyen nueve llamadas a check_stack_overrun(), y el analizador de WKT rechaza explícitamente las GeometryCollection anidadas. La defensa existía en dos caminos paralelos pero nunca se trasladó al de GeoJSON.
Pasos de reproducción
El hallazgo procede de la revisión del código fuente de MariaDB Server (rama main, versión 13.1.0-alpha), y se confirmó con una prueba de concepto en contenedor.
- Conectarse al servidor MariaDB como cualquier usuario con privilegio
SELECT.
- Generar un documento GeoJSON con una
GeometryCollectionmuy anidada. El siguiente script de Python produce una carga con 2000 niveles de anidamiento:
payload = '{"type":"Point","coordinates":[0,0]}'
for i in range(2000):
payload = '{"type":"GeometryCollection","geometries":[' + payload + ']}'
print(payload)
- Ejecutar la consulta pasando esa carga como argumento:
SELECT ST_GeomFromGeoJSON('<carga_anidada_aqui>');
- El proceso del servidor cae con
SIGSEGV(desbordamiento de pila). Todas las conexiones cliente se cortan y hay que reiniciar el servidor.
La cadena de llamadas recursiva es la siguiente: Geometry::create_from_json() (sql/spatial.cc:578) identifica la GeometryCollection y llama a Gis_geometry_collection::init_from_json() (sql/spatial.cc:4447), que a su vez vuelve a llamar a create_from_json() (sql/spatial.cc:4474) por cada geometría interna. El bucle se repite sin límite:
Item_func_geometry_from_json::val_str() -- sql/item_geofunc.cc:175
-> Geometry::create_from_json() -- sql/spatial.cc:578
json_scan_start(je, ...) -- reinicia je->stack_p = 0 (linea 754)
-> Gis_geometry_collection::init_from_json() -- sql/spatial.cc:4447
-> create_from_json() -- sql/spatial.cc:4474 (RECURSA)
Cada nivel de recursión consume unos 300 a 500 bytes de pila C. Con el thread_stack por defecto (entre 256KB y 1MB), bastan aproximadamente entre 650 y 2500 niveles para agotarla. El límite de profundidad del motor JSON (32) no ayuda: en la línea 754, create_from_json() llama a json_scan_start(), que reinicia el contador stack_p a 0 en cada llamada recursiva, así que el límite nunca se acumula. Tampoco existe ninguna llamada a check_stack_overrun() en toda esta cadena.
En la prueba de concepto, un contenedor con MariaDB 12.2.2 (thread_stack de 299008 bytes) cayó con código de salida 139 (128 + 11 = SIGSEGV) al recibir una carga de 90 KB con 2000 niveles de anidamiento.
Impacto
Un único usuario autenticado con el privilegio más básico (SELECT) podía tumbar el servidor MariaDB completo con una sola consulta. No es una caída por conexión: al ser un proceso único multihilo, el desbordamiento de pila en cualquier hilo mata a todo mysqld. Todos los clientes conectados pierden su sesión y las transacciones sin confirmar se revierten.
La carga es pequeña (menos de 1 MB para 2000 niveles) y se puede repetir en cuanto el servidor reinicia, lo que permite una denegación de servicio sostenida.
El investigador señala dos vías de ataque adicionales:
- A través de aplicaciones web: cualquier aplicación que pase GeoJSON aportado por el usuario a
ST_GeomFromGeoJSON()(habitual en aplicaciones de mapas y GIS) abre un vector de ataque no autenticado contra la base de datos. - Cascada por replicación: con replicación basada en sentencias (SBR), la consulta maliciosa se replica a todos los esclavos y también los tumba, de modo que una sola consulta puede derribar toda la topología de replicación.
Remediación
El investigador recomienda añadir check_stack_overrun(current_thd, STACK_MIN_SIZE, NULL) a la entrada de Gis_geometry_collection::init_from_json() (línea 4447 de sql/spatial.cc), siguiendo el patrón ya usado en sql/item_jsonfunc.cc. Como alternativa o de forma complementaria, rechazar las GeometryCollection anidadas en la ruta de GeoJSON igual que ya se hace en la ruta de WKT (sql/spatial.cc:4337-4341, con el error "Unexpected GEOMETRYCOLLECTION").
Afectaba a todas las versiones de MariaDB desde la 10.2.4 (cuando se introdujo ST_GeomFromGeoJSON) hasta la 13.1.0-alpha. El reporte, enviado el 29 de mayo de 2026 al programa de MariaDB, se marcó como resuelto y se divulgó públicamente el 3 de septiembre de 2026, con severidad "media".