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这个值的数据访问。所以加上一个越界判断

  • 相关阅读:
    java程序员必读的书籍(适合于本人)
    面试第三天
    sql常用的函数(持续更新中)
    linux 常用命令
    drf的Response返回字符串有问题
    celery pip仓库上的代码有问题 请使用git上最新版
    PyCrypto已放弃维护 请使用PyCryptodome
    django+celery实现异步任务
    利用Oh-My-Zsh打造你的超级终端---待排版
    pycharm搭配docker本地调试
  • 原文地址:https://www.cnblogs.com/likaiming/p/10887177.html
Copyright © 2011-2022 走看看