diff --git a/qubes/ext/block.py b/qubes/ext/block.py index 05865aeb5..506597853 100644 --- a/qubes/ext/block.py +++ b/qubes/ext/block.py @@ -32,7 +32,7 @@ import qubes.device_protocol import qubes.devices import qubes.ext -from qubes.ext.utils import device_list_change, confirm_device_attachment +from qubes.ext import utils from qubes.storage import Storage name_re = re.compile(r"\A[a-z0-9-]{1,12}\Z") @@ -324,7 +324,7 @@ def on_qdb_change(self, vm, event, path): current_devices = dict( (dev.port_id, device_attachments.get(dev.port_id, None)) for dev in self.on_device_list_block(vm, None)) - device_list_change(self, current_devices, vm, path, BlockDevice) + utils.device_list_change(self, current_devices, vm, path, BlockDevice) @staticmethod def get_device_attachments(vm_): @@ -569,7 +569,10 @@ async def attach_and_notify(self, vm, assignment): # bypass DeviceCollection logic preventing double attach device = assignment.device if assignment.mode.value == "ask-to-attach": - if vm.name != confirm_device_attachment(device, {vm: assignment}): + allowed = await utils.confirm_device_attachment( + device, {vm: assignment}) + allowed = allowed.strip() + if vm.name != allowed: return self.on_device_pre_attached_block( vm, 'device-pre-attach:block', device, assignment.options) diff --git a/qubes/ext/utils.py b/qubes/ext/utils.py index 4bf6ec2b7..ec0f43f86 100644 --- a/qubes/ext/utils.py +++ b/qubes/ext/utils.py @@ -86,7 +86,8 @@ def device_list_change( if len(frontends) > 1: # unique device = tuple(frontends.values())[0].device - target_name = confirm_device_attachment(device, frontends) + target_name = asyncio.ensure_future( + confirm_device_attachment(device, frontends)).result() for front in frontends: if front.name == target_name: target = front @@ -140,17 +141,21 @@ def compare_device_cache(vm, devices_cache, current_devices): return added, attached, detached, removed -def confirm_device_attachment(device, frontends) -> str: +async def confirm_device_attachment(device, frontends) -> str: try: + front_names = [f.name for f in frontends.keys()] # pylint: disable=consider-using-with - proc = subprocess.Popen( - ["attach-confirm", device.backend_domain.name, - device.port_id, device.description, - *[f.name for f in frontends.keys()]], - stdout=subprocess.PIPE, stderr=subprocess.PIPE + # vm names are safe to just join by spaces + proc = await asyncio.create_subprocess_shell( + " ".join(["attach-confirm", device.backend_domain.name, + device.port_id, "'" + device.description + "'", *front_names]), + stdout=asyncio.subprocess.PIPE ) - (target_name, _) = proc.communicate() - return target_name.decode() + (target_name, _) = await proc.communicate() + target_name = target_name.decode() + if target_name in front_names: + return target_name + return "" except Exception as exc: print("attach-confirm", exc, file=sys.stderr) return ""