diff --git a/core/qubesutils.py b/core/qubesutils.py index 417a609d..27455bca 100644 --- a/core/qubesutils.py +++ b/core/qubesutils.py @@ -476,7 +476,7 @@ def usb_encode_device_for_qdb(device): """ encode actual device name (xenstore doesn't allow dot in key names, so translated it into underscore) """ return device.replace('.', '_') -def usb_list_vm(vm): +def usb_list_vm(qvmc, vm): if not vm.is_running(): return {} @@ -512,7 +512,12 @@ def usb_list_vm(vm): "Invalid %s device 'connected-to' in VM '%s'" % ( dev_name, vm.name) continue - connected_to = untrusted_connected_to + connected_to = qvmc.get_vm_by_name(untrusted_connected_to) + if connected_to is None: + print >>sys.stderr, \ + "Device {} appears to be connected to {}, " \ + "but such VM doesn't exist".format( + dev_name, untrusted_connected_to) else: connected_to = None @@ -531,7 +536,7 @@ def usb_list_vm(vm): return devices -def usb_list(qvmc=None, vm=None): +def usb_list(qvmc, vm=None): """ Returns a dictionary of USB devices (for PVUSB backends running in all VM). The dictionary is keyed by 'name' (see below), each element is a dictionary itself: @@ -546,16 +551,14 @@ def usb_list(qvmc=None, vm=None): else: vm_list = [vm] else: - if qvmc is None: - raise QubesException("You must pass either qvm or vm argument") vm_list = qvmc.values() devices_list = {} for vm in vm_list: - devices_list.update(usb_list_vm(vm)) + devices_list.update(usb_list_vm(qvmc, vm)) return devices_list -def usb_check_attached(device): +def usb_check_attached(qvmc, device): """Reread device attachment status""" vm = device['vm'] untrusted_connected_to = vm.qdb.read( @@ -565,22 +568,27 @@ def usb_check_attached(device): raise QubesException( "Invalid %s device 'connected-to' in VM '%s'" % ( device['device'], vm.name)) - connected_to = untrusted_connected_to + connected_to = qvmc.get_vm_by_name(untrusted_connected_to) + if connected_to is None: + print >>sys.stderr, \ + "Device {} appears to be connected to {}, " \ + "but such VM doesn't exist".format( + device['device'], untrusted_connected_to) else: connected_to = None return connected_to -def usb_attach(vm, device, auto_detach=False, wait=True): +def usb_attach(qvmc, vm, device, auto_detach=False, wait=True): if not vm.is_running(): raise QubesException("VM {} not running".format(vm.name)) if not device['vm'].is_running(): raise QubesException("VM {} not running".format(device['vm'].name)) - connected_to = usb_check_attached(device) + connected_to = usb_check_attached(qvmc, device) if connected_to: if auto_detach: - usb_detach(device) + usb_detach(qvmc, device) else: raise QubesException("Device {} already connected, to {}".format( device['name'], connected_to @@ -629,12 +637,13 @@ def usb_attach(vm, device, auto_detach=False, wait=True): f.seek(0) f.write(''.join(policy)) -def usb_detach(vm, device): - connected_to = usb_check_attached(device) +def usb_detach(qvmc, vm, device): + connected_to = usb_check_attached(qvmc, device) # detect race conditions; there is still race here, but much smaller - if vm.name != connected_to: + if connected_to is None or connected_to.qid != vm.qid: raise QubesException( - "Device {} not connected to VM {}".format(device['name'], vm.name)) + "Device {} not connected to VM {}".format( + device['name'], vm.name)) p = vm.run_service('qubes.USBDetach', passio_popen=True, user='root') (stdout, stderr) = p.communicate( diff --git a/qvm-tools/qvm-usb b/qvm-tools/qvm-usb index 3faa7b25..32abf3bd 100755 --- a/qvm-tools/qvm-usb +++ b/qvm-tools/qvm-usb @@ -97,7 +97,7 @@ def main(): backend_vm = qvm_collection.get_vm_by_name(args[1].split(":")[0]) if backend_vm is None: parser.error("No such VM: {}".format(args[1].split(":")[0])) - dev_list = usb_list(vm=backend_vm) + dev_list = usb_list(qvm_collection, vm=backend_vm) if not args[1] in dev_list.keys(): parser.error("Invalid device name: %s" % args[1]) dev = dev_list[args[1]] @@ -108,7 +108,7 @@ def main(): # kwargs['frontend'] = options.frontend kwargs['auto_detach'] = options.auto_detach try: - usb_attach(vm, dev, **kwargs) + usb_attach(qvm_collection, vm, dev, **kwargs) except QubesException as e: print >> sys.stderr, "ERROR: %s" % str(e) sys.exit(1) @@ -125,7 +125,7 @@ def main(): # kwargs['frontend'] = options.frontend # usb_detach(vm, **kwargs) #else: - usb_detach_all(vm) + usb_detach_all(qvm_collection, vm) else: # Maybe usbvm:device? @@ -137,25 +137,24 @@ def main(): backend_vm = qvm_collection.get_vm_by_name(args[0].split(":")[0]) if backend_vm is None: parser.error("No such VM: {}".format(args[0].split(":")[0])) - dev_list = usb_list(vm=backend_vm) + dev_list = usb_list(qvm_collection, vm=backend_vm) if not args[0] in dev_list.keys(): parser.error("Invalid device name: %s" % args[0]) dev = dev_list[args[0]] - attached_to = usb_check_attached(dev) + attached_to = usb_check_attached(qvm_collection, dev) if attached_to is None: print >> sys.stderr, "WARNING: Device not connected to any VM" exit(0) - vm = qvm_collection.get_vm_by_name(attached_to) - usb_detach(vm, dev) + usb_detach(qvm_collection, attached_to, dev) else: if len(args) > 0: parser.error("Too many parameters") # do_list - for dev in usb_list(qvmc=qvm_collection).values(): - attached_to = usb_check_attached(dev) + for dev in usb_list(qvm_collection).values(): + attached_to = dev['connected-to'] attached_to_str = "" if attached_to: - attached_to_str = " (attached to %s)" % (attached_to) + attached_to_str = " (attached to %s)" % (attached_to.name) print "%s\t%s%s" % (dev['name'], dev['desc'], attached_to_str) exit (0)