From ac852d967558cc6b274c98bb128ccef078fea5e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Marczykowski-G=C3=B3recki?= Date: Sat, 18 Jul 2026 03:09:42 +0200 Subject: [PATCH 1/2] ext/block: don't crash on iterating RemoteVM It doesn't have libvirt_domain attribute, so skip it early when looking to where a given device is attached. QubesOS/qubes-issues#10915 --- qubes/ext/block.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qubes/ext/block.py b/qubes/ext/block.py index 37f024708..6e5756962 100644 --- a/qubes/ext/block.py +++ b/qubes/ext/block.py @@ -219,7 +219,7 @@ def attachment(self) -> Optional[QubesVM]: if not self.backend_domain or not self.backend_domain.is_running(): return None for vm in self.backend_domain.app.domains: - if not vm.is_running(): + if not vm.is_running() or not hasattr(vm, "libvirt_domain"): continue if self._is_attached_to(vm): return vm From 9fa3b63ea7c12eebc75518efe649527fb47b2a56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Marczykowski-G=C3=B3recki?= Date: Sat, 18 Jul 2026 03:10:39 +0200 Subject: [PATCH 2/2] api/admin: do not crash on accessing devices for RemoteVM RemoteVM doesn't have devices. When listing devices (either exposed or attached) simply return an empty list (this was already mostly done, but one place was missing). But when trying to attach/detach, return an error early. Fixes: aa714dd8 "Fix devices and other behavior for remotevms" Fixes QubesOS/qubes-issues#10915 --- qubes/api/admin.py | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/qubes/api/admin.py b/qubes/api/admin.py index 03c2ba952..bc6dcd866 100644 --- a/qubes/api/admin.py +++ b/qubes/api/admin.py @@ -1912,9 +1912,12 @@ async def vm_device_list(self, endpoint): async def vm_device_attached(self, endpoint): devclass = endpoint try: - device_assignments = self.dest.devices[ - devclass - ].get_attached_devices() + if self.dest.klass == "RemoteVM": + device_assignments = [] + else: + device_assignments = self.dest.devices[ + devclass + ].get_attached_devices() except AttributeError as e: if e.name == "devices": # shutdown in progress, return specific error @@ -1984,6 +1987,9 @@ async def vm_device_assign(self, endpoint, untrusted_payload): options=assignment.options, ) + if not hasattr(self.dest, "devices"): + raise qubes.exc.QubesException("This qube doesn't support devices") + await self.dest.devices[devclass].assign(assignment) self.app.save() @@ -2026,6 +2032,9 @@ async def vm_device_unassign(self, endpoint): self.fire_event_for_permission(device=dev) + if not hasattr(self.dest, "devices"): + raise qubes.exc.QubesException("This qube doesn't support devices") + await self.dest.devices[devclass].unassign(assignment) self.app.save() @@ -2054,6 +2063,9 @@ async def vm_device_attach(self, endpoint, untrusted_payload): device=dev, mode=assignment.mode.value, options=assignment.options ) + if not hasattr(self.dest, "devices"): + raise qubes.exc.QubesException("This qube doesn't support devices") + await self.dest.devices[devclass].attach(assignment) # Attach/Detach action can modify only a volatile state of running VM. @@ -2076,6 +2088,9 @@ async def vm_device_detach(self, endpoint): self.fire_event_for_permission(device=dev) + if not hasattr(self.dest, "devices"): + raise qubes.exc.QubesException("This qube doesn't support devices") + assignment = qubes.device_protocol.DeviceAssignment(dev) await self.dest.devices[devclass].detach(assignment)