When installing a KVM-internal memslot, delete the non-SMM memslot if
creating the SMM memslot fails. Leaving the non-SMM memslot in-place
makes it impossible for userspace to recover (not that any VMM tries), as
subsequent tries to install the internal memslot will fail with -EEXIST.
Fixes: 9da0e4d5ac96 ("KVM: x86: work on all available address spaces")
Signed-off-by: Sean Christopherson <[email protected]>
---
arch/x86/kvm/x86.c | 32 +++++++++++++++++++++++---------
1 file changed, 23 insertions(+), 9 deletions(-)
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 489631686ba6..326f8a9a5d18 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -10006,6 +10006,19 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long
type)
return ret;
}
+static int x86_set_internal_memslot(struct kvm *kvm, int id, int as_id,
+ gpa_t gpa, unsigned long hva, u32 size)
+{
+ struct kvm_userspace_memory_region2 m;
+
+ m.slot = id | (as_id << 16);
+ m.flags = 0;
+ m.guest_phys_addr = gpa;
+ m.userspace_addr = hva;
+ m.memory_size = size;
+ return kvm_set_internal_memslot(kvm, &m);
+}
+
/**
* __x86_set_memory_region: Setup KVM internal memory slot
*
@@ -10062,16 +10075,17 @@ void __user * __x86_set_memory_region(struct kvm
*kvm, int id, gpa_t gpa,
}
for (i = 0; i < kvm_arch_nr_memslot_as_ids(kvm); i++) {
- struct kvm_userspace_memory_region2 m;
+ r = x86_set_internal_memslot(kvm, id, i, gpa, hva, size);
+ if (!r)
+ continue;
- m.slot = id | (i << 16);
- m.flags = 0;
- m.guest_phys_addr = gpa;
- m.userspace_addr = hva;
- m.memory_size = size;
- r = kvm_set_internal_memslot(kvm, &m);
- if (r < 0)
- return ERR_PTR_USR(r);
+ if (size) {
+ for (i--; i >= 0; i--)
+ x86_set_internal_memslot(kvm, id, i, gpa, 0, 0);
+
+ vm_munmap(hva, size);
+ }
+ return ERR_PTR_USR(r);
}
return (void __user *)hva;
--
2.56.0.385.gac671c819a-goog