| From 2ee3757424be7c1cd1d0bbfa6db29a7edd82a250 Mon Sep 17 00:00:00 2001 |
| From: Sean Christopherson <seanjc@google.com> |
| Date: Mon, 12 Apr 2021 15:20:48 -0700 |
| Subject: KVM: Destroy I/O bus devices on unregister failure _after_ sync'ing SRCU |
| |
| From: Sean Christopherson <seanjc@google.com> |
| |
| commit 2ee3757424be7c1cd1d0bbfa6db29a7edd82a250 upstream. |
| |
| If allocating a new instance of an I/O bus fails when unregistering a |
| device, wait to destroy the device until after all readers are guaranteed |
| to see the new null bus. Destroying devices before the bus is nullified |
| could lead to use-after-free since readers expect the devices on their |
| reference of the bus to remain valid. |
| |
| Fixes: f65886606c2d ("KVM: fix memory leak in kvm_io_bus_unregister_dev()") |
| Cc: stable@vger.kernel.org |
| Signed-off-by: Sean Christopherson <seanjc@google.com> |
| Message-Id: <20210412222050.876100-2-seanjc@google.com> |
| Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| virt/kvm/kvm_main.c | 10 +++++++--- |
| 1 file changed, 7 insertions(+), 3 deletions(-) |
| |
| --- a/virt/kvm/kvm_main.c |
| +++ b/virt/kvm/kvm_main.c |
| @@ -4487,7 +4487,13 @@ void kvm_io_bus_unregister_dev(struct kv |
| new_bus->dev_count--; |
| memcpy(new_bus->range + i, bus->range + i + 1, |
| flex_array_size(new_bus, range, new_bus->dev_count - i)); |
| - } else { |
| + } |
| + |
| + rcu_assign_pointer(kvm->buses[bus_idx], new_bus); |
| + synchronize_srcu_expedited(&kvm->srcu); |
| + |
| + /* Destroy the old bus _after_ installing the (null) bus. */ |
| + if (!new_bus) { |
| pr_err("kvm: failed to shrink bus, removing it completely\n"); |
| for (j = 0; j < bus->dev_count; j++) { |
| if (j == i) |
| @@ -4496,8 +4502,6 @@ void kvm_io_bus_unregister_dev(struct kv |
| } |
| } |
| |
| - rcu_assign_pointer(kvm->buses[bus_idx], new_bus); |
| - synchronize_srcu_expedited(&kvm->srcu); |
| kfree(bus); |
| return; |
| } |