4f371cb8c3
Fix VNC TLS crash (bz 544305) Fix USB devices with high bus/addr values (bz 542639) Fix save/restore with non-root guests (bz 534143, bz 532654) Fix USB devices attached via virt-manager (bz 537227)
497 lines
16 KiB
Diff
497 lines
16 KiB
Diff
diff -rup libvirt-0.7.1/src/hostusb.c new/src/hostusb.c
|
|
--- libvirt-0.7.1/src/hostusb.c 2010-05-17 16:53:48.740748000 -0400
|
|
+++ new/src/hostusb.c 2010-05-17 16:57:19.294731000 -0400
|
|
@@ -37,9 +37,10 @@
|
|
#include "util.h"
|
|
#include "virterror_internal.h"
|
|
|
|
+#define USB_SYSFS "/sys/bus/usb"
|
|
#define USB_DEVFS "/dev/bus/usb/"
|
|
-#define USB_ID_LEN 10 /* "XXXX XXXX" */
|
|
-#define USB_ADDR_LEN 8 /* "XXX:XXX" */
|
|
+#define USB_ID_LEN 10 /* "1234 5678" */
|
|
+#define USB_ADDR_LEN 8 /* "123:456" */
|
|
|
|
struct _usbDevice {
|
|
unsigned bus;
|
|
@@ -57,6 +58,101 @@ struct _usbDevice {
|
|
virReportErrorHelper(conn, VIR_FROM_NONE, code, __FILE__, \
|
|
__FUNCTION__, __LINE__, fmt)
|
|
|
|
+static int usbSysReadFile(virConnectPtr conn,
|
|
+ const char *f_name, const char *d_name,
|
|
+ int base, unsigned *value)
|
|
+{
|
|
+ int ret = -1, tmp;
|
|
+ char *buf = NULL;
|
|
+ char *filename = NULL;
|
|
+ char *ignore = NULL;
|
|
+
|
|
+ tmp = virAsprintf(&filename, USB_SYSFS "/devices/%s/%s", d_name, f_name);
|
|
+ if (tmp < 0) {
|
|
+ virReportOOMError(conn);
|
|
+ goto error;
|
|
+ }
|
|
+
|
|
+ if (virFileReadAll(filename, 1024, &buf) < 0)
|
|
+ goto error;
|
|
+
|
|
+ if (virStrToLong_ui(buf, &ignore, base, value) < 0) {
|
|
+ usbReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
+ _("Could not parse usb file %s"), filename);
|
|
+ goto error;
|
|
+ }
|
|
+
|
|
+ ret = 0;
|
|
+error:
|
|
+ VIR_FREE(filename);
|
|
+ VIR_FREE(buf);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int usbFindBusByVendor(virConnectPtr conn,
|
|
+ unsigned vendor, unsigned product,
|
|
+ unsigned *bus, unsigned *devno)
|
|
+{
|
|
+ DIR *dir = NULL;
|
|
+ int ret = -1, found = 0;
|
|
+ char *ignore = NULL;
|
|
+ struct dirent *de;
|
|
+
|
|
+ dir = opendir(USB_SYSFS "/devices");
|
|
+ if (!dir) {
|
|
+ virReportSystemError(conn, errno,
|
|
+ _("Could not open directory %s"),
|
|
+ USB_SYSFS "/devices");
|
|
+ goto error;
|
|
+ }
|
|
+
|
|
+ while ((de = readdir(dir))) {
|
|
+ unsigned found_prod, found_vend;
|
|
+ if (de->d_name[0] == '.' || strchr(de->d_name, ':'))
|
|
+ continue;
|
|
+
|
|
+ if (usbSysReadFile(conn, "idVendor", de->d_name,
|
|
+ 16, &found_vend) < 0)
|
|
+ goto error;
|
|
+ if (usbSysReadFile(conn, "idProduct", de->d_name,
|
|
+ 16, &found_prod) < 0)
|
|
+ goto error;
|
|
+
|
|
+ if (found_prod == product && found_vend == vendor) {
|
|
+ /* Lookup bus.addr info */
|
|
+ char *tmpstr = de->d_name;
|
|
+ unsigned found_bus, found_addr;
|
|
+
|
|
+ if (STREQ(de->d_name, "usb"))
|
|
+ tmpstr += 3;
|
|
+
|
|
+ if (virStrToLong_ui(tmpstr, &ignore, 10, &found_bus) < 0) {
|
|
+ usbReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
+ _("Failed to parse dir name '%s'"),
|
|
+ de->d_name);
|
|
+ goto error;
|
|
+ }
|
|
+
|
|
+ if (usbSysReadFile(conn, "devnum", de->d_name,
|
|
+ 10, &found_addr) < 0)
|
|
+ goto error;
|
|
+
|
|
+ *bus = found_bus;
|
|
+ *devno = found_addr;
|
|
+ found = 1;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (!found)
|
|
+ usbReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
+ _("Did not find USB device %x:%x"), vendor, product);
|
|
+ else
|
|
+ ret = 0;
|
|
+
|
|
+error:
|
|
+ return ret;
|
|
+}
|
|
|
|
usbDevice *
|
|
usbGetDevice(virConnectPtr conn,
|
|
@@ -86,6 +182,21 @@ usbGetDevice(virConnectPtr conn,
|
|
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(virConnectPtr conn ATTRIBUTE_UNUSED, usbDevice *dev)
|
|
{
|
|
@@ -93,6 +204,18 @@ usbFreeDevice(virConnectPtr conn ATTRIBU
|
|
VIR_FREE(dev);
|
|
}
|
|
|
|
+unsigned usbDeviceGetBus(usbDevice *dev)
|
|
+{
|
|
+ return dev->bus;
|
|
+}
|
|
+
|
|
+
|
|
+unsigned usbDeviceGetDevno(usbDevice *dev)
|
|
+{
|
|
+ return dev->dev;
|
|
+}
|
|
+
|
|
+
|
|
|
|
int usbDeviceFileIterate(virConnectPtr conn,
|
|
usbDevice *dev,
|
|
diff -rup libvirt-0.7.1/src/hostusb.h new/src/hostusb.h
|
|
--- libvirt-0.7.1/src/hostusb.h 2009-09-10 09:45:00.000000000 -0400
|
|
+++ new/src/hostusb.h 2010-05-17 16:58:06.553924000 -0400
|
|
@@ -27,11 +27,16 @@
|
|
|
|
typedef struct _usbDevice usbDevice;
|
|
|
|
-usbDevice *usbGetDevice (virConnectPtr conn,
|
|
- unsigned bus,
|
|
- unsigned devno);
|
|
-void usbFreeDevice (virConnectPtr conn,
|
|
- usbDevice *dev);
|
|
+usbDevice *usbGetDevice(virConnectPtr conn,
|
|
+ unsigned bus,
|
|
+ unsigned devno);
|
|
+usbDevice *usbFindDevice(virConnectPtr conn,
|
|
+ unsigned vendor,
|
|
+ unsigned product);
|
|
+void usbFreeDevice (virConnectPtr conn, usbDevice *dev);
|
|
+
|
|
+unsigned usbDeviceGetBus(usbDevice *dev);
|
|
+unsigned usbDeviceGetDevno(usbDevice *dev);
|
|
|
|
/*
|
|
* Callback that will be invoked once for each file
|
|
diff -rup libvirt-0.7.1/src/libvirt_private.syms new/src/libvirt_private.syms
|
|
--- libvirt-0.7.1/src/libvirt_private.syms 2010-05-17 16:53:48.401831000 -0400
|
|
+++ new/src/libvirt_private.syms 2010-05-17 16:55:03.001748000 -0400
|
|
@@ -441,7 +441,10 @@ virFileMatchesNameSuffix;
|
|
|
|
# usb.h
|
|
usbGetDevice;
|
|
+usbFindDevice;
|
|
usbFreeDevice;
|
|
+usbDeviceGetBus;
|
|
+usbDeviceGetDevno;
|
|
usbDeviceFileIterate;
|
|
|
|
# uuid.h
|
|
diff -rup libvirt-0.7.1/src/qemu_driver.c new/src/qemu_driver.c
|
|
--- libvirt-0.7.1/src/qemu_driver.c 2010-05-17 16:53:48.785743000 -0400
|
|
+++ new/src/qemu_driver.c 2010-05-17 17:06:40.575145000 -0400
|
|
@@ -1493,16 +1493,13 @@ qemuUpdateActivePciHostdevs(struct qemud
|
|
}
|
|
|
|
static int
|
|
-qemuPrepareHostDevices(virConnectPtr conn,
|
|
- struct qemud_driver *driver,
|
|
- virDomainDefPtr def)
|
|
+qemuPrepareHostPCIDevices(virConnectPtr conn,
|
|
+ struct qemud_driver *driver,
|
|
+ virDomainDefPtr def)
|
|
{
|
|
pciDeviceList *pcidevs;
|
|
int i;
|
|
|
|
- if (!def->nhostdevs)
|
|
- return 0;
|
|
-
|
|
if (!(pcidevs = qemuGetPciHostDeviceList(conn, def)))
|
|
return -1;
|
|
|
|
@@ -1792,14 +1789,11 @@ static int qemuDomainSetHostdevUSBOwners
|
|
struct qemuFileOwner owner = { uid, gid };
|
|
int ret = -1;
|
|
|
|
- /* XXX what todo for USB devs assigned based on product/vendor ? Doom :-( */
|
|
- if (!def->source.subsys.u.usb.bus ||
|
|
- !def->source.subsys.u.usb.device)
|
|
- return 0;
|
|
-
|
|
usbDevice *dev = usbGetDevice(conn,
|
|
def->source.subsys.u.usb.bus,
|
|
- def->source.subsys.u.usb.device);
|
|
+ def->source.subsys.u.usb.device,
|
|
+ def->source.subsys.u.usb.vendor,
|
|
+ def->source.subsys.u.usb.product);
|
|
|
|
if (!dev)
|
|
goto cleanup;
|
|
@@ -2065,13 +2059,17 @@ static int qemudStartVMDaemon(virConnect
|
|
return -1;
|
|
}
|
|
|
|
+ DEBUG0("Preparing host devices");
|
|
+ if (qemuPrepareHostDevices(conn, driver, vm->def) < 0)
|
|
+ goto cleanup;
|
|
+
|
|
/* If you are using a SecurityDriver with dynamic labelling,
|
|
then generate a security label for isolation */
|
|
if (vm->def->seclabel.type == VIR_DOMAIN_SECLABEL_DYNAMIC &&
|
|
driver->securityDriver &&
|
|
driver->securityDriver->domainGenSecurityLabel &&
|
|
driver->securityDriver->domainGenSecurityLabel(conn, vm) < 0)
|
|
- return -1;
|
|
+ return cleanup;
|
|
|
|
/* Ensure no historical cgroup for this VM is lieing around bogus settings */
|
|
qemuRemoveCgroup(conn, driver, vm);
|
|
@@ -2119,9 +2117,6 @@ static int qemudStartVMDaemon(virConnect
|
|
if (qemuSetupCgroup(conn, driver, vm) < 0)
|
|
goto cleanup;
|
|
|
|
- if (qemuPrepareHostDevices(conn, driver, vm->def) < 0)
|
|
- goto cleanup;
|
|
-
|
|
if (VIR_ALLOC(vm->monitor_chr) < 0) {
|
|
virReportOOMError(conn);
|
|
goto cleanup;
|
|
@@ -2348,6 +2343,56 @@ retry:
|
|
}
|
|
|
|
|
|
+
|
|
+static int
|
|
+qemuPrepareHostUSBDevices(struct qemud_driver *driver ATTRIBUTE_UNUSED,
|
|
+ virDomainDefPtr def)
|
|
+{
|
|
+ int i;
|
|
+ for (i = 0 ; i < def->nhostdevs ; i++) {
|
|
+ virDomainHostdevDefPtr hostdev = def->hostdevs[i];
|
|
+
|
|
+ if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
|
|
+ continue;
|
|
+ if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB)
|
|
+ continue;
|
|
+
|
|
+ /* 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);
|
|
+
|
|
+ if (!usb)
|
|
+ return -1;
|
|
+
|
|
+ hostdev->source.subsys.u.usb.bus = usbDeviceGetBus(usb);
|
|
+ hostdev->source.subsys.u.usb.device = usbDeviceGetDevno(usb);
|
|
+
|
|
+ usbFreeDevice(usb);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int
|
|
+qemuPrepareHostDevices(struct qemud_driver *driver,
|
|
+ virDomainDefPtr def)
|
|
+{
|
|
+ if (!def->nhostdevs)
|
|
+ return 0;
|
|
+
|
|
+ if (qemuPrepareHostPCIDevices(driver, def) < 0)
|
|
+ return -1;
|
|
+
|
|
+ if (qemuPrepareHostUSBDevices(driver, def) < 0)
|
|
+ return -1;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+
|
|
static void
|
|
qemudDispatchVMEvent(int watch, int fd, int events, void *opaque) {
|
|
struct qemud_driver *driver = opaque;
|
|
@@ -6294,6 +6339,23 @@ static int qemudDomainDetachHostDevice(v
|
|
return -1;
|
|
}
|
|
|
|
+ /* 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
|
|
+ = usbFindDevice(hostdev->source.subsys.u.usb.vendor,
|
|
+ hostdev->source.subsys.u.usb.product);
|
|
+
|
|
+ if (!usb)
|
|
+ return -1;
|
|
+
|
|
+ hostdev->source.subsys.u.usb.bus = usbDeviceGetBus(usb);
|
|
+ hostdev->source.subsys.u.usb.device = usbDeviceGetDevno(usb);
|
|
+
|
|
+ usbFreeDevice(usb);
|
|
+ }
|
|
+
|
|
+
|
|
if (driver->securityDriver &&
|
|
driver->securityDriver->domainSetSecurityHostdevLabel(conn, vm, dev->data.hostdev) < 0)
|
|
VIR_WARN0("Failed to restore device labelling");
|
|
diff -rup libvirt-0.7.1/src/security_selinux.c new/src/security_selinux.c
|
|
--- libvirt-0.7.1/src/security_selinux.c 2010-05-17 16:53:48.775745000 -0400
|
|
+++ new/src/security_selinux.c 2010-05-17 16:58:47.442604000 -0400
|
|
@@ -482,20 +482,15 @@ SELinuxSetSecurityHostdevLabel(virConnec
|
|
|
|
switch (dev->source.subsys.type) {
|
|
case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB: {
|
|
- if (dev->source.subsys.u.usb.bus && dev->source.subsys.u.usb.device) {
|
|
- usbDevice *usb = usbGetDevice(conn,
|
|
- dev->source.subsys.u.usb.bus,
|
|
- dev->source.subsys.u.usb.device);
|
|
-
|
|
- if (!usb)
|
|
- goto done;
|
|
-
|
|
- ret = usbDeviceFileIterate(conn, usb, SELinuxSetSecurityUSBLabel, vm);
|
|
- usbFreeDevice(conn, usb);
|
|
- } else {
|
|
- /* XXX deal with product/vendor better */
|
|
- ret = 0;
|
|
- }
|
|
+ usbDevice *usb = usbGetDevice(conn,
|
|
+ dev->source.subsys.u.usb.bus,
|
|
+ dev->source.subsys.u.usb.device);
|
|
+
|
|
+ if (!usb)
|
|
+ goto done;
|
|
+
|
|
+ ret = usbDeviceFileIterate(conn, usb, SELinuxSetSecurityUSBLabel, vm);
|
|
+ usbFreeDevice(conn, usb);
|
|
break;
|
|
}
|
|
|
|
diff -rup libvirt-0.7.1/src/hostusb.c new/src/hostusb.c
|
|
--- libvirt-0.7.1/src/hostusb.c 2010-05-17 17:09:02.573638000 -0400
|
|
+++ new/src/hostusb.c 2010-05-17 17:29:49.133509000 -0400
|
|
@@ -184,16 +184,17 @@ usbGetDevice(virConnectPtr conn,
|
|
|
|
|
|
usbDevice *
|
|
-usbFindDevice(unsigned vendor,
|
|
+usbFindDevice(virConnectPtr conn,
|
|
+ unsigned vendor,
|
|
unsigned product)
|
|
{
|
|
unsigned bus = 0, devno = 0;
|
|
|
|
- if (usbFindBusByVendor(vendor, product, &bus, &devno) < 0) {
|
|
+ if (usbFindBusByVendor(conn, vendor, product, &bus, &devno) < 0) {
|
|
return NULL;
|
|
}
|
|
|
|
- return usbGetDevice(bus, devno);
|
|
+ return usbGetDevice(conn, bus, devno);
|
|
}
|
|
|
|
|
|
diff -rup libvirt-0.7.1/src/qemu_driver.c new/src/qemu_driver.c
|
|
--- libvirt-0.7.1/src/qemu_driver.c 2010-05-17 17:09:02.602638000 -0400
|
|
+++ new/src/qemu_driver.c 2010-05-17 17:36:10.066214000 -0400
|
|
@@ -1791,9 +1791,7 @@ static int qemuDomainSetHostdevUSBOwners
|
|
|
|
usbDevice *dev = usbGetDevice(conn,
|
|
def->source.subsys.u.usb.bus,
|
|
- def->source.subsys.u.usb.device,
|
|
- def->source.subsys.u.usb.vendor,
|
|
- def->source.subsys.u.usb.product);
|
|
+ def->source.subsys.u.usb.device);
|
|
|
|
if (!dev)
|
|
goto cleanup;
|
|
@@ -2026,6 +2024,10 @@ qemuPrepareMonitorChr(virConnectPtr conn
|
|
return 0;
|
|
}
|
|
|
|
+static int
|
|
+qemuPrepareHostDevices(struct qemud_driver *driver,
|
|
+ virDomainDefPtr def);
|
|
+
|
|
static int qemudStartVMDaemon(virConnectPtr conn,
|
|
struct qemud_driver *driver,
|
|
virDomainObjPtr vm,
|
|
@@ -2060,7 +2062,7 @@ static int qemudStartVMDaemon(virConnect
|
|
}
|
|
|
|
DEBUG0("Preparing host devices");
|
|
- if (qemuPrepareHostDevices(conn, driver, vm->def) < 0)
|
|
+ if (qemuPrepareHostDevices(driver, vm->def) < 0)
|
|
goto cleanup;
|
|
|
|
/* If you are using a SecurityDriver with dynamic labelling,
|
|
@@ -2069,7 +2071,7 @@ static int qemudStartVMDaemon(virConnect
|
|
driver->securityDriver &&
|
|
driver->securityDriver->domainGenSecurityLabel &&
|
|
driver->securityDriver->domainGenSecurityLabel(conn, vm) < 0)
|
|
- return cleanup;
|
|
+ goto cleanup;
|
|
|
|
/* Ensure no historical cgroup for this VM is lieing around bogus settings */
|
|
qemuRemoveCgroup(conn, driver, vm);
|
|
@@ -2360,7 +2362,8 @@ qemuPrepareHostUSBDevices(struct qemud_d
|
|
/* Resolve a vendor/product to bus/device */
|
|
if (hostdev->source.subsys.u.usb.vendor) {
|
|
usbDevice *usb
|
|
- = usbFindDevice(hostdev->source.subsys.u.usb.vendor,
|
|
+ = usbFindDevice(NULL,
|
|
+ hostdev->source.subsys.u.usb.vendor,
|
|
hostdev->source.subsys.u.usb.product);
|
|
|
|
if (!usb)
|
|
@@ -2369,7 +2372,7 @@ qemuPrepareHostUSBDevices(struct qemud_d
|
|
hostdev->source.subsys.u.usb.bus = usbDeviceGetBus(usb);
|
|
hostdev->source.subsys.u.usb.device = usbDeviceGetDevno(usb);
|
|
|
|
- usbFreeDevice(usb);
|
|
+ usbFreeDevice(NULL, usb);
|
|
}
|
|
}
|
|
|
|
@@ -2383,7 +2386,7 @@ qemuPrepareHostDevices(struct qemud_driv
|
|
if (!def->nhostdevs)
|
|
return 0;
|
|
|
|
- if (qemuPrepareHostPCIDevices(driver, def) < 0)
|
|
+ if (qemuPrepareHostPCIDevices(NULL, driver, def) < 0)
|
|
return -1;
|
|
|
|
if (qemuPrepareHostUSBDevices(driver, def) < 0)
|
|
@@ -6343,7 +6346,8 @@ static int qemudDomainDetachHostDevice(v
|
|
if (hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB &&
|
|
hostdev->source.subsys.u.usb.vendor) {
|
|
usbDevice *usb
|
|
- = usbFindDevice(hostdev->source.subsys.u.usb.vendor,
|
|
+ = usbFindDevice(NULL,
|
|
+ hostdev->source.subsys.u.usb.vendor,
|
|
hostdev->source.subsys.u.usb.product);
|
|
|
|
if (!usb)
|
|
@@ -6352,7 +6356,7 @@ static int qemudDomainDetachHostDevice(v
|
|
hostdev->source.subsys.u.usb.bus = usbDeviceGetBus(usb);
|
|
hostdev->source.subsys.u.usb.device = usbDeviceGetDevno(usb);
|
|
|
|
- usbFreeDevice(usb);
|
|
+ usbFreeDevice(NULL, usb);
|
|
}
|
|
|
|
|