From bd289293604d6f33e9fb89196f0b19117ce81f89 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 20 Mar 2024 17:45:29 +0100 Subject: [PATCH 032/100] RAMBlock: make guest_memfd require uncoordinated discard RH-Author: Paolo Bonzini RH-MergeRequest: 245: SEV-SNP support RH-Jira: RHEL-39544 RH-Acked-by: Thomas Huth RH-Acked-by: Bandan Das RH-Acked-by: Vitaly Kuznetsov RH-Commit: [32/91] 0c005849026c334737b88cbd20a0ac237dfca37e (bonzini/rhel-qemu-kvm) Some subsystems like VFIO might disable ram block discard, but guest_memfd uses discard operations to implement conversions between private and shared memory. Because of this, sequences like the following can result in stale IOMMU mappings: 1. allocate shared page 2. convert page shared->private 3. discard shared page 4. convert page private->shared 5. allocate shared page 6. issue DMA operations against that shared page This is not a use-after-free, because after step 3 VFIO is still pinning the page. However, DMA operations in step 6 will hit the old mapping that was allocated in step 1. Address this by taking ram_block_discard_is_enabled() into account when deciding whether or not to discard pages. Since kvm_convert_memory()/guest_memfd doesn't implement a RamDiscardManager handler to convey and replay discard operations, this is a case of uncoordinated discard, which is blocked/released by ram_block_discard_require(). Interestingly, this function had no use so far. Alternative approaches would be to block discard of shared pages, but this would cause guests to consume twice the memory if they use VFIO; or to implement a RamDiscardManager and only block uncoordinated discard, i.e. use ram_block_coordinated_discard_require(). [Commit message mostly by Michael Roth ] Signed-off-by: Paolo Bonzini (cherry picked from commit 852f0048f3ea9f14de18eb279a99fccb6d250e8f) Signed-off-by: Paolo Bonzini --- system/physmem.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/system/physmem.c b/system/physmem.c index f5dfa20e57..5ebcf5be11 100644 --- a/system/physmem.c +++ b/system/physmem.c @@ -1846,6 +1846,13 @@ static void ram_block_add(RAMBlock *new_block, Error **errp) assert(kvm_enabled()); assert(new_block->guest_memfd < 0); + if (ram_block_discard_require(true) < 0) { + error_setg_errno(errp, errno, + "cannot set up private guest memory: discard currently blocked"); + error_append_hint(errp, "Are you using assigned devices?\n"); + goto out_free; + } + new_block->guest_memfd = kvm_create_guest_memfd(new_block->max_length, 0, errp); if (new_block->guest_memfd < 0) { @@ -2109,6 +2116,7 @@ static void reclaim_ramblock(RAMBlock *block) if (block->guest_memfd >= 0) { close(block->guest_memfd); + ram_block_discard_require(false); } g_free(block); -- 2.39.3