Análisis de la Vulnerabilidad CVE-2018-19985 en el Kernel de Linux

Introducción a la Vulnerabilidad

En versiones del kernel de Linux anteriores a la 4.19.8, se identificó una falla en la función hso_probe() del controlador USB para dispositivos móviles de alta velocidad. Esta función lee el valor if_num desde un dispositivo USB como un entero de 8 bits sin realizar una verificación de límites en el array correspondiente. Esto puede ocasionar una lectura fuera de los límites de la memoria en las funciones hso_probe() o hso_get_config_data(). Un atacante con acceso físico al sistema y un dispositivo USB malicioso podría provocar un bloqueo del sistema y una danegación de servicio.

Análisis del Parche Correctivo

El parche que corrige esta vulnerabilidad se encuentra en el commit del kernel con ID 5146f95df782b0ac61abde36567e718692725c89. A continuación se muestra un extracto de los cambios realizados en el archivo drivers/net/usb/hso.c:

diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c
index 184c24b..d6916f7 100644
--- a/drivers/net/usb/hso.c
+++ b/drivers/net/usb/hso.c
@@ -2807,6 +2807,12 @@ static int hso_get_config_data(struct usb_interface *interface)
         return -EIO;
     }
 
+    /* Verificar si la interfaz es válida */
+    if (if_num > 16) {
+        kfree(config_data);
+        return -EINVAL;
+    }
+
     switch (config_data[if_num]) {
     case 0x0:
         result = 0;
@@ -2877,10 +2883,18 @@ static int hso_probe(struct usb_interface *interface,
 
     /* Obtener la especificación de interfaz/puerto desde driver_info o del dispositivo */
-    if (id->driver_info)
+    if (id->driver_info) {
+        /* if_num es controlado por el dispositivo, driver_info es un array terminado en 0. 
+         * Asegurar que el acceso esté dentro de los límites */
+        for (i = 0; i <= if_num; ++i)
+            if (((u32 *)(id->driver_info))[i] == 0)
+                goto exit;
         port_spec = ((u32 *)(id->driver_info))[if_num];
-    else
+    } else {
         port_spec = hso_get_config_data(interface);
+        if (port_spec < 0)
+            goto exit;
+    }
 
     /* Verificar si se necesita cambiar a interfaces alternativas antes de la configuración del puerto */

El parche agrega una validación de límites para if_num en ambas funciones. En hso_get_config_data(), se comprueba que if_num no exceda 16 antes de usarlo como índice. En hso_probe(), se implementa un bucle para recorrer el array driver_info y evitar accesos fuera de rango.

Análisis del Código Fuente

El archivo drivers/net/usb/hso.c implementa el controlador para dispositivos móviles de alta velocidad vía USB. Está compilado con la opción CONFIG_USB_HSO y contiene funciones de inicialización y limpieza del módulo.

module_init(hso_init);
module_exit(hso_exit);

MODULE_AUTHOR(MOD_AUTHOR);
MODULE_DESCRIPTION(MOD_DESCRIPTION);
MODULE_LICENSE(MOD_LICENSE);

La función de inicialización hso_init registra controladores USB y TTY, mientras que hso_exit los desregistra:

static void __exit hso_exit(void)
{
    printk(KERN_INFO "hso: unloaded\n");
    tty_unregister_driver(tty_drv);
    usb_deregister(&hso_driver);
}

El controlador actúa como un puente entre la capa USB y TTY, proporcionando operaciones de serie como apertura, escritura y control de flujo. Estas operaciones se definen en una estructura tty_operations:

static const struct tty_operations hso_serial_ops = {
    .open = hso_serial_open,
    .close = hso_serial_close,
    .write = hso_serial_write,
    .write_room = hso_serial_write_room,
    .ioctl = hso_serial_ioctl,
    .set_termios = hso_serial_set_termios,
    .chars_in_buffer = hso_serial_chars_in_buffer,
    .tiocmget = hso_serial_tiocmget,
    .tiocmset = hso_serial_tiocmset,
    .get_icount = hso_get_count,
    .unthrottle = hso_unthrottle
};

La función hso_probe es el punto de entrada cuando se conecta un dispositivo USB. En ella, se lee el valor if_num desde el descriptor de la interfaz USB:

if_num = interface->altsetting->desc.bInterfaceNumber;

Este valor proviene del dispositivo y puede ser manipulado por un atacante. Sin validación, se usa directamente como índice en ((u32 *)(id->driver_info))[if_num] o en config_data[if_num], lo que lleva a la vulnerabilidad. En hso_get_config_data(), se emplea un buffer local config_data de 17 elementos, y el acceso sin comprobación de límites permite lecturas fuera de rango.

Etiquetas: Linux Kernel CVE-2018-19985 USB driver hso driver security vulnerability

Publicado el 6-14 17:30