On Mon, Mar 28, 2022 at 10:26:55PM +0000, Sean Christopherson wrote: > On Thu, Mar 10, 2022, Chao Peng wrote: > > @@ -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. > > > 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; > } > > > + 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 > >