Re: [PATCH v5 06/13] KVM: Use kvm_userspace_memory_region_ext
From: Chao Peng <hidden>
Date: 2022-04-08 13:59:02
Also in:
kvm, linux-fsdevel, linux-mm, lkml, qemu-devel
On Mon, Mar 28, 2022 at 10:26:55PM +0000, Sean Christopherson wrote:
On Thu, Mar 10, 2022, Chao Peng wrote:quoted
@@ -4476,14 +4477,23 @@ static long kvm_vm_ioctl(struct file *filp, break; } case KVM_SET_USER_MEMORY_REGION: { - struct kvm_userspace_memory_region kvm_userspace_mem; + struct kvm_userspace_memory_region_ext region_ext;It's probably a good idea to zero initialize the full region to avoid consuming garbage stack data if there's a bug and an _ext field is accessed without first checking KVM_MEM_PRIVATE. I'm usually opposed to unnecessary initialization, but this seems like something we could screw up quite easily.quoted
r = -EFAULT; - if (copy_from_user(&kvm_userspace_mem, argp, - sizeof(kvm_userspace_mem))) + if (copy_from_user(®ion_ext, argp, + sizeof(struct kvm_userspace_memory_region))) goto out; + if (region_ext.region.flags & KVM_MEM_PRIVATE) { + int offset = offsetof( + struct kvm_userspace_memory_region_ext, + private_offset); + if (copy_from_user(®ion_ext.private_offset, + argp + offset, + sizeof(region_ext) - offset))In this patch, KVM_MEM_PRIVATE should result in an -EINVAL as it's not yet supported. Copying the _ext on KVM_MEM_PRIVATE belongs in the "Expose KVM_MEM_PRIVATE" patch.
Agreed.
Mechnically, what about first reading flags via get_user(), and then doing a single copy_from_user()? It's technically more work in the common case, and requires an extra check to guard against TOCTOU attacks, but this isn't a fast path by any means and IMO the end result makes it easier to understand the relationship between KVM_MEM_PRIVATE and the two different structs.
Will use this code, thanks for typing. Chao
E.g. case KVM_SET_USER_MEMORY_REGION: { struct kvm_user_mem_region region; unsigned long size; u32 flags; memset(®ion, 0, sizeof(region)); r = -EFAULT; if (get_user(flags, (u32 __user *)(argp + offsetof(typeof(region), flags)))) goto out; if (flags & KVM_MEM_PRIVATE) size = sizeof(struct kvm_userspace_memory_region_ext); else size = sizeof(struct kvm_userspace_memory_region); if (copy_from_user(®ion, argp, size)) goto out; r = -EINVAL; if ((flags ^ region.flags) & KVM_MEM_PRIVATE) goto out; r = kvm_vm_ioctl_set_memory_region(kvm, ®ion); break; }quoted
+ goto out; + } - r = kvm_vm_ioctl_set_memory_region(kvm, &kvm_userspace_mem); + r = kvm_vm_ioctl_set_memory_region(kvm, ®ion_ext); break; } case KVM_GET_DIRTY_LOG: { -- 2.17.1