diff mbox series

[Part2,v6,25/49] KVM: SVM: Disallow registering memory range from HugeTLB for SNP guest

Message ID b32e0daab8af130a1bda76eb06ecd2546e8478bb.1655761627.git.ashish.kalra@amd.com
State New
Headers show
Series Add AMD Secure Nested Paging (SEV-SNP) | expand

Commit Message

Ashish Kalra June 20, 2022, 11:07 p.m. UTC
From: Brijesh Singh <brijesh.singh@amd.com>

While creating the VM, userspace call the KVM_MEMORY_ENCRYPT_REG_REGION
ioctl to register the memory regions for the guest. This registered
memory region is typically used as a guest RAM. Later, the guest may
issue the page state change (PSC) request that will require splitting
the large page into smaller page. If the memory is allocated from the
HugeTLB then hypervisor will not be able to split it.

Do not allow registering the memory range backed by the HugeTLB until
the hypervisor support is added to handle the case.

Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
---
 arch/x86/kvm/svm/sev.c | 37 +++++++++++++++++++++++++++++++++++++
 1 file changed, 37 insertions(+)

Comments

Vlastimil Babka Aug. 4, 2022, 1:37 p.m. UTC | #1
On 6/21/22 01:07, Ashish Kalra wrote:
> From: Brijesh Singh <brijesh.singh@amd.com>
> 
> While creating the VM, userspace call the KVM_MEMORY_ENCRYPT_REG_REGION
> ioctl to register the memory regions for the guest. This registered
> memory region is typically used as a guest RAM. Later, the guest may
> issue the page state change (PSC) request that will require splitting
> the large page into smaller page. If the memory is allocated from the
> HugeTLB then hypervisor will not be able to split it.
> 
> Do not allow registering the memory range backed by the HugeTLB until
> the hypervisor support is added to handle the case.
> 
> Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
> ---
>  arch/x86/kvm/svm/sev.c | 37 +++++++++++++++++++++++++++++++++++++
>  1 file changed, 37 insertions(+)
> 
> diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c
> index 9e6fc7a94ed7..41b83aa6b5f4 100644
> --- a/arch/x86/kvm/svm/sev.c
> +++ b/arch/x86/kvm/svm/sev.c
> @@ -17,6 +17,7 @@
>  #include <linux/misc_cgroup.h>
>  #include <linux/processor.h>
>  #include <linux/trace_events.h>
> +#include <linux/hugetlb.h>
>  
>  #include <asm/pkru.h>
>  #include <asm/trapnr.h>
> @@ -2007,6 +2008,35 @@ int sev_mem_enc_ioctl(struct kvm *kvm, void __user *argp)
>  	return r;
>  }
>  
> +static bool is_range_hugetlb(struct kvm *kvm, struct kvm_enc_region *range)
> +{
> +	struct vm_area_struct *vma;
> +	u64 start, end;
> +	bool ret = true;
> +
> +	start = range->addr;
> +	end = start + range->size;
> +
> +	mmap_read_lock(kvm->mm);
> +
> +	do {
> +		vma = find_vma_intersection(kvm->mm, start, end);
> +		if (!vma)
> +			goto unlock;
> +
> +		if (is_vm_hugetlb_page(vma))
> +			goto unlock;
> +
> +		start = vma->vm_end;
> +	} while (end > vma->vm_end);

Note it's more efficient to only find the first vma and then iterate using
vma->vm_next. But the details will change when maple tree is merged, and
likely this patch won't exist after rebasing to UPM anyway...

> +	ret = false;
> +
> +unlock:
> +	mmap_read_unlock(kvm->mm);
> +	return ret;
> +}
> +
>  int sev_mem_enc_register_region(struct kvm *kvm,
>  				struct kvm_enc_region *range)
>  {
> @@ -2024,6 +2054,13 @@ int sev_mem_enc_register_region(struct kvm *kvm,
>  	if (range->addr > ULONG_MAX || range->size > ULONG_MAX)
>  		return -EINVAL;
>  
> +	/*
> +	 * SEV-SNP does not support the backing pages from the HugeTLB. Verify
> +	 * that the registered memory range is not from the HugeTLB.
> +	 */
> +	if (sev_snp_guest(kvm) && is_range_hugetlb(kvm, range))
> +		return -EINVAL;
> +
>  	region = kzalloc(sizeof(*region), GFP_KERNEL_ACCOUNT);
>  	if (!region)
>  		return -ENOMEM;
diff mbox series

Patch

diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c
index 9e6fc7a94ed7..41b83aa6b5f4 100644
--- a/arch/x86/kvm/svm/sev.c
+++ b/arch/x86/kvm/svm/sev.c
@@ -17,6 +17,7 @@ 
 #include <linux/misc_cgroup.h>
 #include <linux/processor.h>
 #include <linux/trace_events.h>
+#include <linux/hugetlb.h>
 
 #include <asm/pkru.h>
 #include <asm/trapnr.h>
@@ -2007,6 +2008,35 @@  int sev_mem_enc_ioctl(struct kvm *kvm, void __user *argp)
 	return r;
 }
 
+static bool is_range_hugetlb(struct kvm *kvm, struct kvm_enc_region *range)
+{
+	struct vm_area_struct *vma;
+	u64 start, end;
+	bool ret = true;
+
+	start = range->addr;
+	end = start + range->size;
+
+	mmap_read_lock(kvm->mm);
+
+	do {
+		vma = find_vma_intersection(kvm->mm, start, end);
+		if (!vma)
+			goto unlock;
+
+		if (is_vm_hugetlb_page(vma))
+			goto unlock;
+
+		start = vma->vm_end;
+	} while (end > vma->vm_end);
+
+	ret = false;
+
+unlock:
+	mmap_read_unlock(kvm->mm);
+	return ret;
+}
+
 int sev_mem_enc_register_region(struct kvm *kvm,
 				struct kvm_enc_region *range)
 {
@@ -2024,6 +2054,13 @@  int sev_mem_enc_register_region(struct kvm *kvm,
 	if (range->addr > ULONG_MAX || range->size > ULONG_MAX)
 		return -EINVAL;
 
+	/*
+	 * SEV-SNP does not support the backing pages from the HugeTLB. Verify
+	 * that the registered memory range is not from the HugeTLB.
+	 */
+	if (sev_snp_guest(kvm) && is_range_hugetlb(kvm, range))
+		return -EINVAL;
+
 	region = kzalloc(sizeof(*region), GFP_KERNEL_ACCOUNT);
 	if (!region)
 		return -ENOMEM;