Skip to content

Commit 42462d2

Browse files
davidhildenbrandgregkh
authored andcommitted
KVM: kvm_io_bus_unregister_dev() should never fail
commit 90db10434b163e46da413d34db8d0e77404cc645 upstream. No caller currently checks the return value of kvm_io_bus_unregister_dev(). This is evil, as all callers silently go on freeing their device. A stale reference will remain in the io_bus, getting at least used again, when the iobus gets teared down on kvm_destroy_vm() - leading to use after free errors. There is nothing the callers could do, except retrying over and over again. So let's simply remove the bus altogether, print an error and make sure no one can access this broken bus again (returning -ENOMEM on any attempt to access it). Fixes: e93f8a0 ("KVM: convert io_bus to SRCU") Reported-by: Dmitry Vyukov <dvyukov@google.com> Reviewed-by: Cornelia Huck <cornelia.huck@de.ibm.com> Signed-off-by: David Hildenbrand <david@redhat.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 3a1246b commit 42462d2

3 files changed

Lines changed: 27 additions & 20 deletions

File tree

include/linux/kvm_host.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -182,8 +182,8 @@ int kvm_io_bus_read(struct kvm_vcpu *vcpu, enum kvm_bus bus_idx, gpa_t addr,
182182
int len, void *val);
183183
int kvm_io_bus_register_dev(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr,
184184
int len, struct kvm_io_device *dev);
185-
int kvm_io_bus_unregister_dev(struct kvm *kvm, enum kvm_bus bus_idx,
186-
struct kvm_io_device *dev);
185+
void kvm_io_bus_unregister_dev(struct kvm *kvm, enum kvm_bus bus_idx,
186+
struct kvm_io_device *dev);
187187

188188
#ifdef CONFIG_KVM_ASYNC_PF
189189
struct kvm_async_pf {

virt/kvm/eventfd.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -868,7 +868,8 @@ kvm_deassign_ioeventfd_idx(struct kvm *kvm, enum kvm_bus bus_idx,
868868
continue;
869869

870870
kvm_io_bus_unregister_dev(kvm, bus_idx, &p->dev);
871-
kvm->buses[bus_idx]->ioeventfd_count--;
871+
if (kvm->buses[bus_idx])
872+
kvm->buses[bus_idx]->ioeventfd_count--;
872873
ioeventfd_release(p);
873874
ret = 0;
874875
break;

virt/kvm/kvm_main.c

Lines changed: 23 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -655,7 +655,8 @@ static void kvm_destroy_vm(struct kvm *kvm)
655655
spin_unlock(&kvm_lock);
656656
kvm_free_irq_routing(kvm);
657657
for (i = 0; i < KVM_NR_BUSES; i++) {
658-
kvm_io_bus_destroy(kvm->buses[i]);
658+
if (kvm->buses[i])
659+
kvm_io_bus_destroy(kvm->buses[i]);
659660
kvm->buses[i] = NULL;
660661
}
661662
kvm_coalesced_mmio_free(kvm);
@@ -3273,6 +3274,8 @@ int kvm_io_bus_write(struct kvm_vcpu *vcpu, enum kvm_bus bus_idx, gpa_t addr,
32733274
};
32743275

32753276
bus = srcu_dereference(vcpu->kvm->buses[bus_idx], &vcpu->kvm->srcu);
3277+
if (!bus)
3278+
return -ENOMEM;
32763279
r = __kvm_io_bus_write(vcpu, bus, &range, val);
32773280
return r < 0 ? r : 0;
32783281
}
@@ -3290,6 +3293,8 @@ int kvm_io_bus_write_cookie(struct kvm_vcpu *vcpu, enum kvm_bus bus_idx,
32903293
};
32913294

32923295
bus = srcu_dereference(vcpu->kvm->buses[bus_idx], &vcpu->kvm->srcu);
3296+
if (!bus)
3297+
return -ENOMEM;
32933298

32943299
/* First try the device referenced by cookie. */
32953300
if ((cookie >= 0) && (cookie < bus->dev_count) &&
@@ -3340,6 +3345,8 @@ int kvm_io_bus_read(struct kvm_vcpu *vcpu, enum kvm_bus bus_idx, gpa_t addr,
33403345
};
33413346

33423347
bus = srcu_dereference(vcpu->kvm->buses[bus_idx], &vcpu->kvm->srcu);
3348+
if (!bus)
3349+
return -ENOMEM;
33433350
r = __kvm_io_bus_read(vcpu, bus, &range, val);
33443351
return r < 0 ? r : 0;
33453352
}
@@ -3352,6 +3359,9 @@ int kvm_io_bus_register_dev(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr,
33523359
struct kvm_io_bus *new_bus, *bus;
33533360

33543361
bus = kvm->buses[bus_idx];
3362+
if (!bus)
3363+
return -ENOMEM;
3364+
33553365
/* exclude ioeventfd which is limited by maximum fd */
33563366
if (bus->dev_count - bus->ioeventfd_count > NR_IOBUS_DEVS - 1)
33573367
return -ENOSPC;
@@ -3371,45 +3381,41 @@ int kvm_io_bus_register_dev(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr,
33713381
}
33723382

33733383
/* Caller must hold slots_lock. */
3374-
int kvm_io_bus_unregister_dev(struct kvm *kvm, enum kvm_bus bus_idx,
3375-
struct kvm_io_device *dev)
3384+
void kvm_io_bus_unregister_dev(struct kvm *kvm, enum kvm_bus bus_idx,
3385+
struct kvm_io_device *dev)
33763386
{
3377-
int i, r;
3387+
int i;
33783388
struct kvm_io_bus *new_bus, *bus;
33793389

33803390
bus = kvm->buses[bus_idx];
3381-
3382-
/*
3383-
* It's possible the bus being released before hand. If so,
3384-
* we're done here.
3385-
*/
33863391
if (!bus)
3387-
return 0;
3392+
return;
33883393

3389-
r = -ENOENT;
33903394
for (i = 0; i < bus->dev_count; i++)
33913395
if (bus->range[i].dev == dev) {
3392-
r = 0;
33933396
break;
33943397
}
33953398

3396-
if (r)
3397-
return r;
3399+
if (i == bus->dev_count)
3400+
return;
33983401

33993402
new_bus = kmalloc(sizeof(*bus) + ((bus->dev_count - 1) *
34003403
sizeof(struct kvm_io_range)), GFP_KERNEL);
3401-
if (!new_bus)
3402-
return -ENOMEM;
3404+
if (!new_bus) {
3405+
pr_err("kvm: failed to shrink bus, removing it completely\n");
3406+
goto broken;
3407+
}
34033408

34043409
memcpy(new_bus, bus, sizeof(*bus) + i * sizeof(struct kvm_io_range));
34053410
new_bus->dev_count--;
34063411
memcpy(new_bus->range + i, bus->range + i + 1,
34073412
(new_bus->dev_count - i) * sizeof(struct kvm_io_range));
34083413

3414+
broken:
34093415
rcu_assign_pointer(kvm->buses[bus_idx], new_bus);
34103416
synchronize_srcu_expedited(&kvm->srcu);
34113417
kfree(bus);
3412-
return r;
3418+
return;
34133419
}
34143420

34153421
static struct notifier_block kvm_cpu_notifier = {

0 commit comments

Comments
 (0)