[PATCH 1/4] KVM: guest_memfd: add generic post_populate callback

Nikita Kalyazin posted 4 patches 1 month ago
[PATCH 1/4] KVM: guest_memfd: add generic post_populate callback
Posted by Nikita Kalyazin 1 month ago
This adds a generic implementation of the `post_populate` callback for
the `kvm_gmem_populate`.  The only thing it does is populates the pages
with data provided by userspace if the user pointer is not NULL,
otherwise it clears the pages.
This is supposed to be used by KVM_X86_SW_PROTECTED_VM VMs.

Signed-off-by: Nikita Kalyazin <kalyazin@amazon.com>
---
 virt/kvm/guest_memfd.c | 21 +++++++++++++++++++++
 1 file changed, 21 insertions(+)

diff --git a/virt/kvm/guest_memfd.c b/virt/kvm/guest_memfd.c
index 8f079a61a56d..954312fac462 100644
--- a/virt/kvm/guest_memfd.c
+++ b/virt/kvm/guest_memfd.c
@@ -620,6 +620,27 @@ int kvm_gmem_get_pfn(struct kvm *kvm, struct kvm_memory_slot *slot,
 EXPORT_SYMBOL_GPL(kvm_gmem_get_pfn);
 
 #ifdef CONFIG_KVM_GENERIC_PRIVATE_MEM
+static int kvm_gmem_post_populate_generic(struct kvm *kvm, gfn_t gfn_start, kvm_pfn_t pfn,
+				  void __user *src, int order, void *opaque)
+{
+	int ret = 0, i;
+	int npages = (1 << order);
+	gfn_t gfn;
+
+	if (src) {
+		void *vaddr = kmap_local_pfn(pfn);
+
+		ret = copy_from_user(vaddr, src, npages * PAGE_SIZE);
+		if (ret)
+			ret = -EINVAL;
+		kunmap_local(vaddr);
+	} else
+		for (gfn = gfn_start, i = 0; gfn < gfn_start + npages; gfn++, i++)
+			clear_highpage(pfn_to_page(pfn + i));
+
+	return ret;
+}
+
 long kvm_gmem_populate(struct kvm *kvm, gfn_t start_gfn, void __user *src, long npages,
 		       kvm_gmem_populate_cb post_populate, void *opaque)
 {
-- 
2.40.1
Re: [PATCH 1/4] KVM: guest_memfd: add generic post_populate callback
Posted by Mike Day 3 days, 1 hour ago

On 10/24/24 04:54, Nikita Kalyazin wrote:
> This adds a generic implementation of the `post_populate` callback for
> the `kvm_gmem_populate`.  The only thing it does is populates the pages
> with data provided by userspace if the user pointer is not NULL,
> otherwise it clears the pages.
> This is supposed to be used by KVM_X86_SW_PROTECTED_VM VMs.
> 
> Signed-off-by: Nikita Kalyazin <kalyazin@amazon.com>
> ---
>   virt/kvm/guest_memfd.c | 21 +++++++++++++++++++++
>   1 file changed, 21 insertions(+)
> 
> diff --git a/virt/kvm/guest_memfd.c b/virt/kvm/guest_memfd.c
> index 8f079a61a56d..954312fac462 100644
> --- a/virt/kvm/guest_memfd.c
> +++ b/virt/kvm/guest_memfd.c
> @@ -620,6 +620,27 @@ int kvm_gmem_get_pfn(struct kvm *kvm, struct kvm_memory_slot *slot,
>   EXPORT_SYMBOL_GPL(kvm_gmem_get_pfn);
>   
>   #ifdef CONFIG_KVM_GENERIC_PRIVATE_MEM

KVM_AMD_SEV can select KVM_GENERIC_PRIVATE_MEM, so to guarantee this is only for
software protection it might be good to use:

#if defined CONFIG_KVM_GENERIC_PRIVATE_MEM && !defined CONFIG_KVM_AMD_SEV

That could end up too verbose so there should probably be some more concise mechanism
to guarantee this generic callback isn't used for a hardware-protected guest.

Mike

> +static int kvm_gmem_post_populate_generic(struct kvm *kvm, gfn_t gfn_start, kvm_pfn_t pfn,
> +				  void __user *src, int order, void *opaque)
> +{
> +	int ret = 0, i;
> +	int npages = (1 << order);
> +	gfn_t gfn;
> +
> +	if (src) {
> +		void *vaddr = kmap_local_pfn(pfn);
> +
> +		ret = copy_from_user(vaddr, src, npages * PAGE_SIZE);
> +		if (ret)
> +			ret = -EINVAL;
> +		kunmap_local(vaddr);
> +	} else
> +		for (gfn = gfn_start, i = 0; gfn < gfn_start + npages; gfn++, i++)
> +			clear_highpage(pfn_to_page(pfn + i));
> +
> +	return ret;
> +}
> +
>   long kvm_gmem_populate(struct kvm *kvm, gfn_t start_gfn, void __user *src, long npages,
>   		       kvm_gmem_populate_cb post_populate, void *opaque)
>   {
Re: [PATCH 1/4] KVM: guest_memfd: add generic post_populate callback
Posted by Nikita Kalyazin 8 hours ago
On 22/11/2024 18:40, Mike Day wrote:
> On 10/24/24 04:54, Nikita Kalyazin wrote:
>> This adds a generic implementation of the `post_populate` callback for
>> the `kvm_gmem_populate`.  The only thing it does is populates the pages
>> with data provided by userspace if the user pointer is not NULL,
>> otherwise it clears the pages.
>> This is supposed to be used by KVM_X86_SW_PROTECTED_VM VMs.
>>
>> Signed-off-by: Nikita Kalyazin <kalyazin@amazon.com>
>> ---
>>   virt/kvm/guest_memfd.c | 21 +++++++++++++++++++++
>>   1 file changed, 21 insertions(+)
>>
>> diff --git a/virt/kvm/guest_memfd.c b/virt/kvm/guest_memfd.c
>> index 8f079a61a56d..954312fac462 100644
>> --- a/virt/kvm/guest_memfd.c
>> +++ b/virt/kvm/guest_memfd.c
>> @@ -620,6 +620,27 @@ int kvm_gmem_get_pfn(struct kvm *kvm, struct 
>> kvm_memory_slot *slot,
>>   EXPORT_SYMBOL_GPL(kvm_gmem_get_pfn);
>>
>>   #ifdef CONFIG_KVM_GENERIC_PRIVATE_MEM
> 
> KVM_AMD_SEV can select KVM_GENERIC_PRIVATE_MEM, so to guarantee this is 
> only for
> software protection it might be good to use:
> 
> #if defined CONFIG_KVM_GENERIC_PRIVATE_MEM && !defined CONFIG_KVM_AMD_SEV
> 
> That could end up too verbose so there should probably be some more 
> concise mechanism
> to guarantee this generic callback isn't used for a hardware-protected 
> guest.

Thanks, will make a note for myself for the next iteration.

> 
> Mike