Re: [PATCH v5 06/13] KVM: Use kvm_userspace_memory_region_ext
From: Sean Christopherson <seanjc@google.com>
Date: 2022-03-28 22:27:09
Also in:
kvm, linux-fsdevel, linux-mm, lkml, qemu-devel
On Thu, Mar 10, 2022, Chao Peng wrote:
quoted hunk ↗ jump to hunk
@@ -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.
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.
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