From aeac4d20dc6a616fab9be1124814a731e49212f4 Mon Sep 17 00:00:00 2001 From: Alexandre Bezroutchko Date: Wed, 7 Nov 2012 00:24:05 +0100 Subject: [PATCH 1/5] dom0+vm/usb: bugfix in usb_find_unused_frontend() --- dom0/qvm-core/qubesutils.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/dom0/qvm-core/qubesutils.py b/dom0/qvm-core/qubesutils.py index c84044d4..2711528f 100644 --- a/dom0/qvm-core/qubesutils.py +++ b/dom0/qvm-core/qubesutils.py @@ -578,9 +578,7 @@ def usb_find_unused_frontend(xs_trans, backend_vm_xid, vm_xid, usb_ver): if xs.read(xs_trans, '/local/domain/%d/backend/vusb/%d/%d/usb-ver' % (backend_vm_xid, vm_xid, frontend_dev)) != usb_ver: last_frontend_dev = frontend_dev continue - if xs.read(xs_trans, "%s/backend-id" % fe_path) == str(backend_vm_xid): - last_frontend_dev = frontend_dev - continue + # here: found an existing frontend already connected to right backend using an appropriate USB version ports = xs.ls(xs_trans, '/local/domain/%d/backend/vusb/%d/%d/port' % (backend_vm_xid, vm_xid, frontend_dev)) if ports is None: last_frontend_dev = frontend_dev From 900e5327d26fb8e6cbad1a3454ac30cb4343f8d4 Mon Sep 17 00:00:00 2001 From: Alexandre Bezroutchko Date: Wed, 7 Nov 2012 00:37:50 +0100 Subject: [PATCH 2/5] dom0+vm/usb: improve error reporting in usb_find_unused_frontend() --- dom0/qvm-core/qubesutils.py | 1 + 1 file changed, 1 insertion(+) diff --git a/dom0/qvm-core/qubesutils.py b/dom0/qvm-core/qubesutils.py index 2711528f..06884653 100644 --- a/dom0/qvm-core/qubesutils.py +++ b/dom0/qvm-core/qubesutils.py @@ -581,6 +581,7 @@ def usb_find_unused_frontend(xs_trans, backend_vm_xid, vm_xid, usb_ver): # here: found an existing frontend already connected to right backend using an appropriate USB version ports = xs.ls(xs_trans, '/local/domain/%d/backend/vusb/%d/%d/port' % (backend_vm_xid, vm_xid, frontend_dev)) if ports is None: + print >> sys.stderr, "No ports in VM %d frontend_dev %d?" % (vm_xid, frontend_dev) last_frontend_dev = frontend_dev continue for port in ports: From 14a1f9f67f3c56f6868409afdc7001f2d5519fa5 Mon Sep 17 00:00:00 2001 From: Alexandre Bezroutchko Date: Wed, 7 Nov 2012 00:41:13 +0100 Subject: [PATCH 3/5] dom0+vm/usb: cosmetic - added comments to usb_find_unused_frontend() --- dom0/qvm-core/qubesutils.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dom0/qvm-core/qubesutils.py b/dom0/qvm-core/qubesutils.py index 06884653..079fa70a 100644 --- a/dom0/qvm-core/qubesutils.py +++ b/dom0/qvm-core/qubesutils.py @@ -565,7 +565,10 @@ def usb_find_unused_frontend(xs_trans, backend_vm_xid, vm_xid, usb_ver): Returns frontend specification in - format. """ + # This variable holds an index of last frontend scanned by the loop below. + # If nothing found, this value will be used to derive the index of a new frontend. last_frontend_dev = -1 + frontend_devs = xs.ls(xs_trans, "/local/domain/%d/device/vusb" % vm_xid) if frontend_devs is not None: for frontend_dev in frontend_devs: From 350ff3aaa1a07f9783bcec22853d78252e0641d1 Mon Sep 17 00:00:00 2001 From: Alexandre Bezroutchko Date: Wed, 7 Nov 2012 01:14:12 +0100 Subject: [PATCH 4/5] dom0+vm/usb: encode/decode dots in USB device names when writing/reading xenstore --- dom0/qvm-core/qubesutils.py | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/dom0/qvm-core/qubesutils.py b/dom0/qvm-core/qubesutils.py index 079fa70a..9692629c 100644 --- a/dom0/qvm-core/qubesutils.py +++ b/dom0/qvm-core/qubesutils.py @@ -455,6 +455,14 @@ def usb_setup(backend_vm_xid, vm_xid, devid, usb_ver): xs.transaction_end(trans) +def usb_decode_device_from_xs(xs_encoded_device): + """ recover actual device name (xenstore doesn't allow dot in key names, so it was translated to underscore) """ + return xs_encoded_device.replace('_', '.') + +def usb_encode_device_for_xs(device): + """ encode actual device name (xenstore doesn't allow dot in key names, so translated it into underscore) """ + return device.replace('.', '_') + def usb_list(): """ Returns a dictionary of USB devices (for PVUSB backends running in all VM). @@ -479,20 +487,20 @@ def usb_list(): vm_devices = xs.ls(xs_trans, '/local/domain/%s/qubes-usb-devices' % xid) if vm_devices is None: continue - for device in vm_devices: + # when listing devices in xenstore we get encoded names + for xs_encoded_device in vm_devices: # Sanitize device id - if not device_re.match(device): + if not device_re.match(xs_encoded_device): print >> sys.stderr, "Invalid device id in VM '%s'" % vm_name continue - device_desc = xs.read(xs_trans, '/local/domain/%s/qubes-usb-devices/%s/desc' % (xid, device)) + device = usb_decode_device_from_xs(xs_encoded_device) + device_desc = xs.read(xs_trans, '/local/domain/%s/qubes-usb-devices/%s/desc' % (xid, xs_encoded_device)) if not desc_re.match(device_desc): print >> sys.stderr, "Invalid %s device desc in VM '%s'" % (device, vm_name) continue - # xenstore doesn't allow dot in key names - was translated to underscore - device = device.replace('_', '.') visible_name = "%s:%s" % (vm_name, device) # grab version - usb_ver = xs.read(xs_trans, '/local/domain/%s/qubes-usb-devices/%s/usb-ver' % (xid, device)) + usb_ver = xs.read(xs_trans, '/local/domain/%s/qubes-usb-devices/%s/usb-ver' % (xid, xs_encoded_device)) if usb_ver is None or not usb_ver_re.match(usb_ver): print >> sys.stderr, "Invalid %s device USB version in VM '%s'" % (device, vm_name) continue @@ -539,8 +547,8 @@ def usb_check_attached(xs_trans, backend_vm, device): if not port.isdigit(): print >> sys.stderr, "Invalid port in VM %s frontend %s" % (vm, frontend) continue - dev = xs.read(xs_trans, '/local/domain/%d/backend/vusb/%s/%s/port/%s' % (backend_vm, vm, frontend_dev, port)) - if dev == device: + xs_encoded_dev = xs.read(xs_trans, '/local/domain/%d/backend/vusb/%s/%s/port/%s' % (backend_vm, vm, frontend_dev, port)) + if usb_decode_device_from_xs(xs_encoded_dev) == device: frontend = "%s-%s" % (frontend_dev, port) vm_name = xl_ctx.domid_to_name(int(vm)) if vm_name is None: @@ -592,8 +600,8 @@ def usb_find_unused_frontend(xs_trans, backend_vm_xid, vm_xid, usb_ver): print >> sys.stderr, "Invalid port in VM %d frontend_dev %d" % (vm_xid, frontend_dev) continue port = int(port) - dev = xs.read(xs_trans, '/local/domain/%d/backend/vusb/%d/%d/port/%d' % (backend_vm_xid, vm_xid, frontend_dev, port)) - if dev == "": + xs_encoded_dev = xs.read(xs_trans, '/local/domain/%d/backend/vusb/%d/%d/port/%d' % (backend_vm_xid, vm_xid, frontend_dev, port)) + if xs_encoded_dev == "": return '%d-%d' % (frontend_dev, port) last_frontend_dev = frontend_dev @@ -607,7 +615,8 @@ def usb_attach(vm, backend_vm, device, frontend=None, auto_detach=False, wait=Tr xs_trans = xs.transaction_start() - usb_ver = xs.read(xs_trans, '/local/domain/%s/qubes-usb-devices/%s/usb-ver' % (backend_vm.xid, device)) + xs_encoded_device = usb_encode_device_for_xs(device) + usb_ver = xs.read(xs_trans, '/local/domain/%s/qubes-usb-devices/%s/usb-ver' % (backend_vm.xid, xs_encoded_device)) if usb_ver is None or not usb_ver_re.match(usb_ver): xs.transaction_end(xs_trans) raise QubesException("Invalid %s device USB version in VM '%s'" % (device, backend_vm.name)) From eb193fc8701cf39e21abca26f4f00adacdd09853 Mon Sep 17 00:00:00 2001 From: Alexandre Bezroutchko Date: Wed, 7 Nov 2012 01:33:19 +0100 Subject: [PATCH 5/5] dom0+vm/usb: sanitize data (USB device names) read from xenstore before use --- dom0/qvm-core/qubesutils.py | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/dom0/qvm-core/qubesutils.py b/dom0/qvm-core/qubesutils.py index 9692629c..2fdb731e 100644 --- a/dom0/qvm-core/qubesutils.py +++ b/dom0/qvm-core/qubesutils.py @@ -407,6 +407,7 @@ def block_detach_all(vm, vm_xid = None): ####### USB devices ###### usb_ver_re = re.compile(r"^(1|2)$") +usb_device_re = re.compile(r"^[0-9]+-[0-9]+(_[0-9]+)?$") def usb_setup(backend_vm_xid, vm_xid, devid, usb_ver): """ @@ -473,7 +474,6 @@ def usb_list(): name = :- desc = description """ - device_re = re.compile(r"^[0-9]+-[0-9]+(_[0-9]+)?$") # FIXME: any better idea of desc_re? desc_re = re.compile(r"^.{1,255}$") @@ -490,7 +490,7 @@ def usb_list(): # when listing devices in xenstore we get encoded names for xs_encoded_device in vm_devices: # Sanitize device id - if not device_re.match(xs_encoded_device): + if not usb_device_re.match(xs_encoded_device): print >> sys.stderr, "Invalid device id in VM '%s'" % vm_name continue device = usb_decode_device_from_xs(xs_encoded_device) @@ -544,10 +544,15 @@ def usb_check_attached(xs_trans, backend_vm, device): if ports is None: continue for port in ports: + # FIXME: refactor, see similar loop in usb_find_unused_frontend(), use usb_list() instead? if not port.isdigit(): print >> sys.stderr, "Invalid port in VM %s frontend %s" % (vm, frontend) continue xs_encoded_dev = xs.read(xs_trans, '/local/domain/%d/backend/vusb/%s/%s/port/%s' % (backend_vm, vm, frontend_dev, port)) + # Sanitize device id + if not usb_device_re.match(xs_encoded_dev): + print >> sys.stderr, "Invalid device id in VM %d" % (backend_vm) + continue if usb_decode_device_from_xs(xs_encoded_dev) == device: frontend = "%s-%s" % (frontend_dev, port) vm_name = xl_ctx.domid_to_name(int(vm)) @@ -596,11 +601,16 @@ def usb_find_unused_frontend(xs_trans, backend_vm_xid, vm_xid, usb_ver): last_frontend_dev = frontend_dev continue for port in ports: + # FIXME: refactor, see similar loop in usb_check_attached(), use usb_list() instead? if not port.isdigit(): print >> sys.stderr, "Invalid port in VM %d frontend_dev %d" % (vm_xid, frontend_dev) continue port = int(port) xs_encoded_dev = xs.read(xs_trans, '/local/domain/%d/backend/vusb/%d/%d/port/%d' % (backend_vm_xid, vm_xid, frontend_dev, port)) + # Sanitize device id + if not usb_device_re.match(xs_encoded_dev): + print >> sys.stderr, "Invalid device id in VM %d" % (backend_vm_xid) + continue if xs_encoded_dev == "": return '%d-%d' % (frontend_dev, port) last_frontend_dev = frontend_dev