From 13dab699b1be70f2cc03f07d48e0439c7d17182e Mon Sep 17 00:00:00 2001 From: Christian Helmuth Date: Fri, 26 Nov 2021 17:37:31 +0100 Subject: [PATCH] base: invalidate entire range on VM-session detach The requested guest-physical memory range may comprise multiple attached dataspace regions, which must all be detached. This is not required for the current vbox5 implementation, but for vbox6 as the current API suggests these semantics. This commit can be seen as intermediate fix as a real fix should change the API to prevent long-running detach loops in core that may lock out requests by other components. --- repos/base/src/core/vm_session_common.cc | 31 +++++++++++++++--------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/repos/base/src/core/vm_session_common.cc b/repos/base/src/core/vm_session_common.cc index 0b757dd854..beadc25988 100644 --- a/repos/base/src/core/vm_session_common.cc +++ b/repos/base/src/core/vm_session_common.cc @@ -123,26 +123,35 @@ void Vm_session_component::attach(Dataspace_capability const cap, void Vm_session_component::detach(addr_t guest_phys, size_t size) { - if (guest_phys & 0xffful) { - size += 0x1000 - (guest_phys & 0xffful); - guest_phys &= ~0xffful; + if (!size || (guest_phys & 0xffful) || (size & 0xffful)) { + warning("vm_session: skipping invalid memory detach addr=", + (void *)guest_phys, " size=", (void *)size); + return; } - if (size & 0xffful) - size = align_addr(size, 12); + addr_t const guest_phys_end = guest_phys + (size - 1); + addr_t addr = guest_phys; + do { + Rm_region *region = _map.metadata((void *)addr); - if (!size) - return; + /* walk region holes page-by-page */ + size_t iteration_size = 0x1000; + + if (region) { + iteration_size = region->size(); - { - Rm_region *region = _map.metadata(reinterpret_cast(guest_phys)); - if (region && guest_phys == region->base() && region->size() <= size) { /* inform dataspace */ region->dataspace().detached_from(*region); + /* cleanup metadata */ _map.free(reinterpret_cast(region->base())); } - } + + if (addr >= guest_phys_end - (iteration_size - 1)) + break; + + addr += iteration_size; + } while (true); /* kernel specific code to detach memory from guest */ _detach_vm_memory(guest_phys, size);