From: Zeng Chi kvm_vm_ioctl_register_coalesced_mmio() passes the userspace-provided zone->size (a __u32) straight into kvm_io_bus_register_dev(), which stores the length as an int. A zone with size >= 2^31 is thus stored with a negative length, which has two undesirable effects: - kvm_io_bus_cmp() sign-extends r->len when computing the end of the range, so the zone's computed end either wraps or precedes its start. Depending on registration order, this makes bsearch() miss other devices on the bus, e.g. an ioeventfd registered after the zone, or spuriously match the zone for accesses far outside it. - KVM_UNREGISTER_COALESCED_MMIO passes zone->size as the "len" to coalesced_mmio_in_range(), which rejects negative lengths, so the zone can never be matched for unregistration, i.e. the zone is stuck on the bus until the VM is destroyed, while the ioctl silently returns success. A zone whose addr+size wraps around has the same problems, as both kvm_io_bus_cmp() and coalesced_mmio_in_range() assume non-wrapping ranges. Reject such zones with -EINVAL at registration time, similar to how ioeventfd rejects a wrapping addr+len. Note, this tightens the uAPI slightly, as such zones were previously accepted (and then misbehaved); no known VMM relies on registering a zone that doesn't fit in an int. Signed-off-by: Zeng Chi --- virt/kvm/coalesced_mmio.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/virt/kvm/coalesced_mmio.c b/virt/kvm/coalesced_mmio.c index 6b1d90161099..fcadbf6ee6c9 100644 --- a/virt/kvm/coalesced_mmio.c +++ b/virt/kvm/coalesced_mmio.c @@ -128,6 +128,9 @@ int kvm_vm_ioctl_register_coalesced_mmio(struct kvm *kvm, if (zone->pio != 1 && zone->pio != 0) return -EINVAL; + if (zone->size > INT_MAX || zone->addr + zone->size < zone->addr) + return -EINVAL; + dev = kzalloc_obj(struct kvm_coalesced_mmio_dev, GFP_KERNEL_ACCOUNT); if (!dev) return -ENOMEM; -- 2.25.1 No virus found Checked by Hillstone Network AntiVirus