Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > ebe084c140192657f9094e135a84202c > files > 136

libvirt-0.8.2-29.el5.src.rpm

From 9aebd3448ba4b9726e447a420c0146852c1883e1 Mon Sep 17 00:00:00 2001
From: Guannan Ren <gren@redhat.com>
Date: Wed, 20 Jun 2012 19:19:19 -0600
Subject: [PATCH] usb: create functions to search usb device accurately
To: libvir-list@redhat.com

https://bugzilla.redhat.com/show_bug.cgi?id=816601
CVE-2012-2693

usbFindDevice():get usb device according to
                idVendor, idProduct, bus, device
                it is the exact match of the four parameters

usbFindDeviceByBus():get usb device according to bus, device
                  it returns only one usb device same as usbFindDevice

usbFindDeviceByVendor():get usb device according to idVendor,idProduct
                     it probably returns multiple usb devices.

usbDeviceSearch(): a helper function to do the actual search
(cherry picked from commit 9914477efc9764f691ca50faca6592a2d4fecec8)

Conflicts:
	src/libvirt_private.syms - context shifted location in file
	src/qemu/qemu_hostdev.c - upstream split this out of qemu_driver.c
	src/qemu/qemu_hotplug.c - upstream split this out of qemu_driver.c
	src/util/hostusb.c - no backport of commit 60d769a

Signed-off-by: Daniel Veillard <veillard@redhat.com>
---
 src/libvirt_private.syms |    2 +
 src/qemu/qemu_driver.c   |   28 +++++--
 src/util/hostusb.c       |  203 ++++++++++++++++++++++++++++++++-------------
 src/util/hostusb.h       |   22 ++++--
 4 files changed, 182 insertions(+), 73 deletions(-)

diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index e7d3c7c..3941581 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -773,6 +773,8 @@ usbDeviceListNew;
 usbDeviceListSteal;
 usbDeviceSetUsedBy;
 usbFindDevice;
+usbFindDeviceByBus;
+usbFindDeviceByVendor;
 usbFreeDevice;
 usbGetDevice;
 
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index c925895..d4cf460 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -2982,13 +2982,19 @@ qemuPrepareHostdevUSBDevices(struct qemud_driver *driver,
 
         /* Resolve a vendor/product to bus/device */
         if (hostdev->source.subsys.u.usb.vendor) {
-            usbDevice *usb
-                = usbFindDevice(hostdev->source.subsys.u.usb.vendor,
-                                hostdev->source.subsys.u.usb.product);
+            usbDevice *usb;
+            usbDeviceList *devs;
 
-            if (!usb)
+            devs = usbFindDeviceByVendor(hostdev->source.subsys.u.usb.vendor,
+                                         hostdev->source.subsys.u.usb.product);
+
+            if (!devs)
                 goto cleanup;
 
+            usb = usbDeviceListGet(devs, 0);
+            usbDeviceListSteal(devs, usb);
+            usbDeviceListFree(devs);
+
             if ((tmp = usbDeviceListFind(driver->activeUsbHostdevs, usb))) {
                 const char *other_name = usbDeviceGetUsedBy(tmp);
 
@@ -8239,16 +8245,22 @@ static int qemudDomainAttachHostDevice(struct qemud_driver *driver,
     /* Resolve USB product/vendor to bus/device */
     if (hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB &&
         hostdev->source.subsys.u.usb.vendor) {
+        usbDevice *usb;
+        usbDeviceList *list;
+
         if (qemuPrepareHostdevUSBDevices(driver, vm->def->name, &hostdev, 1) < 0)
             goto error;
 
-        usbDevice *usb
-            = usbFindDevice(hostdev->source.subsys.u.usb.vendor,
-                            hostdev->source.subsys.u.usb.product);
+        list = usbFindDeviceByVendor(hostdev->source.subsys.u.usb.vendor,
+                                     hostdev->source.subsys.u.usb.product);
 
-        if (!usb)
+        if (!list)
             return -1;
 
+        usb = usbDeviceListGet(list, 0);
+        usbDeviceListSteal(list, usb);
+        usbDeviceListFree(list);
+
         hostdev->source.subsys.u.usb.bus = usbDeviceGetBus(usb);
         hostdev->source.subsys.u.usb.device = usbDeviceGetDevno(usb);
 
diff --git a/src/util/hostusb.c b/src/util/hostusb.c
index 667fe99..890e0bf 100644
--- a/src/util/hostusb.c
+++ b/src/util/hostusb.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009-2011 Red Hat, Inc.
+ * Copyright (C) 2009-2012 Red Hat, Inc.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -30,6 +30,7 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <unistd.h>
+#include <stdbool.h>
 
 #include "hostusb.h"
 #include "logging.h"
@@ -42,9 +43,16 @@
 #define USB_ID_LEN 10 /* "1234 5678" */
 #define USB_ADDR_LEN 8 /* "123:456" */
 
+/* For virReportOOMError()  and virReportSystemError() */
+#define VIR_FROM_THIS VIR_FROM_NONE
+
+#define usbReportError(code, ...)                              \
+    virReportErrorHelper(NULL, VIR_FROM_NONE, code, __FILE__,  \
+                         __FUNCTION__, __LINE__, __VA_ARGS__)
+
 struct _usbDevice {
-    unsigned      bus;
-    unsigned      dev;
+    unsigned int      bus;
+    unsigned int      dev;
 
     char          name[USB_ADDR_LEN]; /* domain:bus:slot.function */
     char          id[USB_ID_LEN];     /* product vendor */
@@ -57,15 +65,14 @@ struct _usbDeviceList {
     usbDevice **devs;
 };
 
-/* For virReportOOMError()  and virReportSystemError() */
-#define VIR_FROM_THIS VIR_FROM_NONE
-
-#define usbReportError(code, ...)                              \
-    virReportErrorHelper(NULL, VIR_FROM_NONE, code, __FILE__,  \
-                         __FUNCTION__, __LINE__, __VA_ARGS__)
+typedef enum {
+    USB_DEVICE_ALL = 0,
+    USB_DEVICE_FIND_BY_VENDOR = 1 << 0,
+    USB_DEVICE_FIND_BY_BUS = 1 << 1,
+} usbDeviceFindFlags;
 
 static int usbSysReadFile(const char *f_name, const char *d_name,
-                          int base, unsigned *value)
+                          int base, unsigned int *value)
 {
     int ret = -1, tmp;
     char *buf = NULL;
@@ -94,13 +101,22 @@ cleanup:
     return ret;
 }
 
-static int usbFindBusByVendor(unsigned vendor, unsigned product,
-                              unsigned *bus, unsigned *devno)
+static usbDeviceList *
+usbDeviceSearch(unsigned int vendor,
+                unsigned int product,
+                unsigned int bus,
+                unsigned int devno,
+                unsigned int flags)
 {
     DIR *dir = NULL;
-    int ret = -1, found = 0;
+    bool found = false;
     char *ignore = NULL;
     struct dirent *de;
+    usbDeviceList *list = NULL, *ret = NULL;
+    usbDevice *usb;
+
+    if (!(list = usbDeviceListNew()))
+        goto cleanup;
 
     dir = opendir(USB_SYSFS "/devices");
     if (!dir) {
@@ -111,61 +127,145 @@ static int usbFindBusByVendor(unsigned vendor, unsigned product,
     }
 
     while ((de = readdir(dir))) {
-        unsigned found_prod, found_vend;
+        unsigned int found_prod, found_vend, found_bus, found_devno;
+        char *tmpstr = de->d_name;
+
         if (de->d_name[0] == '.' || strchr(de->d_name, ':'))
             continue;
 
         if (usbSysReadFile("idVendor", de->d_name,
                            16, &found_vend) < 0)
             goto cleanup;
+
         if (usbSysReadFile("idProduct", de->d_name,
                            16, &found_prod) < 0)
             goto cleanup;
 
-        if (found_prod == product && found_vend == vendor) {
-            /* Lookup bus.addr info */
-            char *tmpstr = de->d_name;
-            unsigned found_bus, found_addr;
+        if (STRPREFIX(de->d_name, "usb"))
+            tmpstr += 3;
+
+        if (virStrToLong_ui(tmpstr, &ignore, 10, &found_bus) < 0) {
+            usbReportError(VIR_ERR_INTERNAL_ERROR,
+                           _("Failed to parse dir name '%s'"),
+                           de->d_name);
+            goto cleanup;
+        }
+
+        if (usbSysReadFile("devnum", de->d_name,
+                           10, &found_devno) < 0)
+            goto cleanup;
+
+        if ((flags & USB_DEVICE_FIND_BY_VENDOR) &&
+            (found_prod != product || found_vend != vendor))
+            continue;
 
-            if (STRPREFIX(de->d_name, "usb"))
-                tmpstr += 3;
+        if (flags & USB_DEVICE_FIND_BY_BUS) {
+            if (found_bus != bus || found_devno != devno)
+                continue;
+            found = true;
+        }
 
-            if (virStrToLong_ui(tmpstr, &ignore, 10, &found_bus) < 0) {
-                usbReportError(VIR_ERR_INTERNAL_ERROR,
-                               _("Failed to parse dir name '%s'"),
-                               de->d_name);
-                goto cleanup;
-            }
+        usb = usbGetDevice(found_bus, found_devno);
+        if (!usb)
+            goto cleanup;
 
-            if (usbSysReadFile("devnum", de->d_name,
-                               10, &found_addr) < 0)
-                goto cleanup;
+        if (usbDeviceListAdd(list, usb) < 0) {
+            usbFreeDevice(usb);
+            goto cleanup;
+        }
 
-            *bus = found_bus;
-            *devno = found_addr;
-            found = 1;
+        if (found)
             break;
-        }
     }
-
-    if (!found)
-        usbReportError(VIR_ERR_INTERNAL_ERROR,
-                       _("Did not find USB device %x:%x"), vendor, product);
-    else
-        ret = 0;
+    ret = list;
 
 cleanup:
     if (dir) {
         int saved_errno = errno;
-        closedir (dir);
+        closedir(dir);
         errno = saved_errno;
     }
+
+    if (!ret)
+        usbDeviceListFree(list);
     return ret;
 }
 
+usbDeviceList *
+usbFindDeviceByVendor(unsigned int vendor, unsigned product)
+{
+
+    usbDeviceList *list;
+    if (!(list = usbDeviceSearch(vendor, product, 0 , 0,
+                                 USB_DEVICE_FIND_BY_VENDOR)))
+        return NULL;
+
+    if (list->count == 0) {
+        usbReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("Did not find USB device %x:%x"), vendor, product);
+        usbDeviceListFree(list);
+        return NULL;
+    }
+
+    return list;
+}
+
 usbDevice *
-usbGetDevice(unsigned bus,
-             unsigned devno)
+usbFindDeviceByBus(unsigned int bus, unsigned devno)
+{
+    usbDevice *usb;
+    usbDeviceList *list;
+
+    if (!(list = usbDeviceSearch(0, 0, bus, devno,
+                                 USB_DEVICE_FIND_BY_BUS)))
+        return NULL;
+
+    if (list->count == 0) {
+        usbReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("Did not find USB device bus:%u device:%u"),
+                       bus, devno);
+        usbDeviceListFree(list);
+        return NULL;
+    }
+
+    usb = usbDeviceListGet(list, 0);
+    usbDeviceListSteal(list, usb);
+    usbDeviceListFree(list);
+
+    return usb;
+}
+
+usbDevice *
+usbFindDevice(unsigned int vendor,
+              unsigned int product,
+              unsigned int bus,
+              unsigned int devno)
+{
+    usbDevice *usb;
+    usbDeviceList *list;
+
+    unsigned int flags = USB_DEVICE_FIND_BY_VENDOR|USB_DEVICE_FIND_BY_BUS;
+    if (!(list = usbDeviceSearch(vendor, product, bus, devno, flags)))
+        return NULL;
+
+    if (list->count == 0) {
+        usbReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("Did not find USB device %x:%x bus:%u device:%u"),
+                       vendor, product, bus, devno);
+        usbDeviceListFree(list);
+        return NULL;
+    }
+
+    usb = usbDeviceListGet(list, 0);
+    usbDeviceListSteal(list, usb);
+    usbDeviceListFree(list);
+
+    return usb;
+}
+
+usbDevice *
+usbGetDevice(unsigned int bus,
+             unsigned int devno)
 {
     usbDevice *dev;
 
@@ -207,21 +307,6 @@ usbGetDevice(unsigned bus,
     return dev;
 }
 
-
-usbDevice *
-usbFindDevice(unsigned vendor,
-              unsigned product)
-{
-    unsigned bus = 0, devno = 0;
-
-    if (usbFindBusByVendor(vendor, product, &bus, &devno) < 0) {
-        return NULL;
-    }
-
-    return usbGetDevice(bus, devno);
-}
-
-
 void
 usbFreeDevice(usbDevice *dev)
 {
@@ -247,13 +332,13 @@ const char *usbDeviceGetName(usbDevice *dev)
     return dev->name;
 }
 
-unsigned usbDeviceGetBus(usbDevice *dev)
+unsigned int usbDeviceGetBus(usbDevice *dev)
 {
     return dev->bus;
 }
 
 
-unsigned usbDeviceGetDevno(usbDevice *dev)
+unsigned int usbDeviceGetDevno(usbDevice *dev)
 {
     return dev->dev;
 }
diff --git a/src/util/hostusb.h b/src/util/hostusb.h
index afaa32f..27e07dc 100644
--- a/src/util/hostusb.h
+++ b/src/util/hostusb.h
@@ -28,17 +28,27 @@
 typedef struct _usbDevice usbDevice;
 typedef struct _usbDeviceList usbDeviceList;
 
-usbDevice *usbGetDevice(unsigned bus,
-                        unsigned devno);
-usbDevice *usbFindDevice(unsigned vendor,
-                         unsigned product);
+usbDevice *usbGetDevice(unsigned int bus,
+                        unsigned int devno);
+
+usbDevice *usbFindDeviceByBus(unsigned int bus,
+                              unsigned int devno);
+
+usbDeviceList *usbFindDeviceByVendor(unsigned int vendor,
+                                     unsigned int product);
+
+usbDevice *usbFindDevice(unsigned int vendor,
+                         unsigned int product,
+                         unsigned int bus,
+                         unsigned int devno);
+
 void       usbFreeDevice (usbDevice *dev);
 void       usbDeviceSetUsedBy(usbDevice *dev, const char *name);
 const char *usbDeviceGetUsedBy(usbDevice *dev);
 const char *usbDeviceGetName(usbDevice *dev);
 
-unsigned usbDeviceGetBus(usbDevice *dev);
-unsigned usbDeviceGetDevno(usbDevice *dev);
+unsigned int usbDeviceGetBus(usbDevice *dev);
+unsigned int usbDeviceGetDevno(usbDevice *dev);
 
 /*
  * Callback that will be invoked once for each file
-- 
1.7.7.4