zoukankan      html  css  js  c++  java
  • CVE-2018-19985漏洞学习

    简介

    4.19.8之前,在Linux内核中,hso_probe()函数中发现了一个缺陷,该函数从USB设备(作为u8)读取if_num值,并且不需要对数组进行长度检查就使用它来索引数组,从而导致在hso_probe()或hso_get_config_data()中读取OOB内存。攻击者使用伪造的USB设备和对系统的物理访问(需要连接这样的设备)可以导致系统崩溃和拒绝服务。

    补丁分析

    补丁在这里:https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=5146f95df782b0ac61abde36567e718692725c89

    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;
         }
     
    +    /* check if we have a valid interface */
    +    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,
     
         /* Get the interface/port specification from either driver_info or from
          * the device itself */
    -    if (id->driver_info)
    +    if (id->driver_info) {
    +        /* if_num is controlled by the device, driver_info is a 0 terminated
    +         * array. Make sure, the access is in bounds! */
    +        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;
    +    }
     
         /* Check if we need to switch to alt interfaces prior to port
          * configuration */

    确定问题出在drivers/net/usb/hso.c,分析一下这个文件

    源码分析

    文件最后,有模块的一些操作,文件开头有一些注释,得知这是文件是一个驱动的实现,Option High Speed Mobile Devices,还有一个专门的编译选项CONFIG_USB_HSO

    module_init(hso_init);
    module_exit(hso_exit);
    
    MODULE_AUTHOR(MOD_AUTHOR);
    MODULE_DESCRIPTION(MOD_DESCRIPTION);
    MODULE_LICENSE(MOD_LICENSE);

    初始化函数是hso_init,卸载函数是hso_exit,卸载函数比较简单,只是注销了tty和usb的驱动,同样在hso_init函数中,也注册了这两个驱动。

    static void __exit hso_exit(void)
    {
        printk(KERN_INFO "hso: unloaded
    ");
    
        tty_unregister_driver(tty_drv);
        /* deregister the usb driver */
        usb_deregister(&hso_driver);
    }

    这应该是一个连在USB总线上的串口,下层使用USB来和硬件交流,然后将USB获得的信息传递给tty层。从文件中定义的tty_operations这些个函数看下去,最终实现都是USB这边的实现,usb_submit_urb、usb_control_msg函数

    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
    };

    hso_probe函数是定义的usb驱动的probe函数,就是USB设备插上之后,USB驱动第一个被调用的函数,在这个函数中应该要做一些设备的初始化功能

    static struct usb_driver hso_driver = {
        .name = driver_name,
        .probe = hso_probe,
        .disconnect = hso_disconnect,
        .id_table = hso_ids,
        .suspend = hso_suspend,
        .resume = hso_resume,
        .reset_resume = hso_resume,
        .supports_autosuspend = 1,
    };

    补丁的修改位置就在hso_probe的开头,问题出在if_num处

        if_num = interface->altsetting->desc.bInterfaceNumber;
    
        /* Get the interface/port specification from either driver_info or from
         * the device itself */
        if (id->driver_info)
            port_spec = ((u32 *)(id->driver_info))[if_num];
        else
            port_spec = hso_get_config_data(interface);
    
        if (interface->cur_altsetting->desc.bInterfaceClass != 0xFF) {
            dev_err(&interface->dev, "Not our interface
    ");
            return -ENODEV;
        }

    altsetting,这个值表示可选的设置,bInterfaceNumber表示该配置的接口号。这些值都是USB枚举阶段从外部设备读入的值,也就是if_num这个值是可以被恶意的外部设备所控制

    在port_spec = ((u32 *)(id->driver_info))[if_num];这句话,当id->driver_info==0的时候if_num的超过会造成越界访问,不过好像看了下hso_ids中的值,会有等于0的情况吗?

    然后是hso_get_config_data函数,开头同样有这样的一段和上述代码类似

        struct usb_device *usbdev = interface_to_usbdev(interface);
        u8 config_data[17];
        u32 if_num = interface->altsetting->desc.bInterfaceNumber;
        s32 result;
    
        if (usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0),
                    0x86, 0xC0, 0, 0, config_data, 17,
                    USB_CTRL_SET_TIMEOUT) != 0x11) {
            return -EIO;
        }
    
        switch (config_data[if_num]) {

    同样是对于interface->altsetting->desc.bInterfaceNumber这个值的数据访问。所以加上一个越界判断

  • 相关阅读:
    BZOJ1527 : [POI2005]Pun-point
    2016-2017 ACM-ICPC Southwestern European Regional Programming Contest (SWERC 2016)
    2016-2017 ACM-ICPC Northwestern European Regional Programming Contest (NWERC 2016)
    NAIPC-2016
    BZOJ2498 : Xavier is Learning to Count
    ACM ICPC Vietnam National Second Round
    XVI Open Cup named after E.V. Pankratiev. GP of Ukraine
    XVI Open Cup named after E.V. Pankratiev. GP of Peterhof
    HDU5509 : Pattern String
    BZOJ4583 : 购物
  • 原文地址:https://www.cnblogs.com/likaiming/p/10887177.html
Copyright © 2011-2022 走看看