diff mbox series

[RFC,v1,23/26] KVM: arm64: Check that host unmaps memory unshared by guest

Message ID 20240222161047.402609-24-tabba@google.com (mailing list archive)
State New, archived
Headers show
Series KVM: Restricted mapping of guest_memfd at the host and pKVM/arm64 support | expand

Commit Message

Fuad Tabba Feb. 22, 2024, 4:10 p.m. UTC
After an unshare call from the guest, check that the memory isn't
mapped by the host before returning to the guest.

If the host has acknowledged the unsharing, by marking the memory
as private, but hasn't unmapped it, return an error to the host.

On the other hand if the host has not acknowledged the unsharing,
then return to the guest with an error, indicating that the
unsharing has failed.

Signed-off-by: Fuad Tabba <tabba@google.com>
---
 arch/arm64/kvm/hypercalls.c | 37 +++++++++++++++++++++++++++++++++++++
 1 file changed, 37 insertions(+)
diff mbox series

Patch

diff --git a/arch/arm64/kvm/hypercalls.c b/arch/arm64/kvm/hypercalls.c
index 56fb4fa70eec..23237ca400ec 100644
--- a/arch/arm64/kvm/hypercalls.c
+++ b/arch/arm64/kvm/hypercalls.c
@@ -24,8 +24,45 @@ 
 	f;								\
 })
 
+static int kvm_handle_unshare_return(struct kvm_vcpu *vcpu)
+{
+	gpa_t gpa = vcpu->run->hypercall.args[0];
+	gfn_t gfn = gpa_to_gfn(gpa);
+	struct kvm *kvm = vcpu->kvm;
+
+	if (!IS_ENABLED(CONFIG_KVM_PRIVATE_MEM))
+		return 1;
+
+	if (!kvm_mem_is_private(kvm, gfn)) {
+		/* Inform the guest that host refused to unshare the memory. */
+		vcpu->run->hypercall.ret = SMCCC_RET_INVALID_PARAMETER;
+		WARN_ON(kvm_vm_set_mem_attributes_kernel(vcpu->kvm, gfn, gfn + 1, 0));
+
+		return 1;
+	}
+
+	/*
+	 * Host has acknowledged that the memory has been unshared by marking it
+	 * as private, so check if it still has mapping. If it does, exit back
+	 * to the host to fix it.
+	 * The exit reason should still be preserved.
+	 */
+	if (kvm_is_gmem_mapped(kvm, gfn, gfn + 1))
+		return -EPERM;
+
+	return 1;
+}
+
 int kvm_handle_hypercall_return(struct kvm_vcpu *vcpu)
 {
+	if (vcpu->run->hypercall.ret == SMCCC_RET_SUCCESS &&
+	    vcpu->run->hypercall.nr == ARM_SMCCC_KVM_FUNC_MEM_UNSHARE) {
+		int ret = kvm_handle_unshare_return(vcpu);
+
+		if (ret <= 0)
+			return ret;
+	}
+
 	smccc_set_retval(vcpu, vcpu->run->hypercall.ret,
 			 vcpu->run->hypercall.args[0],
 			 vcpu->run->hypercall.args[1],