Received: by 2002:a05:6a10:206:0:0:0:0 with SMTP id 6csp4546815pxj; Wed, 12 May 2021 07:57:51 -0700 (PDT) X-Google-Smtp-Source: ABdhPJydLeJk8lxJR3j33IFyQfQi0kvTvw6yVmjuUzP5ypVzvcDhCfRSJjjQSIXkZ8dSc0ZAnzXW X-Received: by 2002:aca:3109:: with SMTP id x9mr25974954oix.50.1620831471538; Wed, 12 May 2021 07:57:51 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1620831471; cv=none; d=google.com; s=arc-20160816; b=D51aYgVmLhshqWgjb34EHrojdRBtFSmr3FltTjK3ES96m03uKYnUp839PPQWmXXQeS EQ25Komuu69cizX2lG5BtSILajgKTJN6RjdCsz0+0765tLLL0xvBQNKwXMtTqpoJoj2Y k5hSKqytiFDn4V2cgOFUc5G1mYiLlPkXsVT8bvmLVahidPLAq+Oh2zp6/Ow9cUVl8Fff 7ocAQpHOIWIduizura1hxcbdHBesUQTQpBFyFIk3XZg8TB1gYUhSlv5tGSqGlQylRbrv GXnF231RyIa4/z1lqpb0RAjE3lkWNUG1txdzeTOgmEGKH+N0HfsVvBXNsEMy7b/ELO3V avEg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :user-agent:references:in-reply-to:message-id:date:subject:cc:to :from:dkim-signature; bh=E5uoR/NULVoBI39m5nxcwXvt7A/ZR6iMa+i5233Gm2w=; b=Y9wl2ZfiTRRDYcCvoIhKE0A7cS00/dNqKL6xN9cU6N3YovQkp95RjwKEtQ4hytaryL YsvtCHoW7tuVw3wX2eHt9qsScZpg3xFPD1sarlaJEOkCjGy150grrFU8Fe8RsehB7YLW b1mz6I0yl2oMcbm3HoTGu18eFn//BWpgfm4ECDiptfpBfTZfUtqOi/GOvJ5Z011/xqMs tr3miFZQbMYAOiyEULaba6kFdiyHn5Jz/TqZpYfQrWikl6NQtO7MfAAivM7lGD74ebaU /7sp+oDWVh4KJesmqPumMyT7aOuzaCFW71JKXjp1lARH5zf1g26TVvc56sqAyJ6iXm7o pzXw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linuxfoundation.org header.s=korg header.b=S91v7Ury; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linuxfoundation.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id s83si187112oib.139.2021.05.12.07.57.37; Wed, 12 May 2021 07:57:51 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; dkim=pass header.i=@linuxfoundation.org header.s=korg header.b=S91v7Ury; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linuxfoundation.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232249AbhELO5q (ORCPT + 99 others); Wed, 12 May 2021 10:57:46 -0400 Received: from mail.kernel.org ([198.145.29.99]:47248 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232285AbhELOz6 (ORCPT ); Wed, 12 May 2021 10:55:58 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id EE4D761433; Wed, 12 May 2021 14:54:49 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=linuxfoundation.org; s=korg; t=1620831290; bh=FkNunr8aETry8nGvdB4T3sS6pGXdfxMPr3Tpyub4fxs=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=S91v7UryIFzRtRGRFnOO7BSln3a1gOKaeOgQLnZUxyzQGRFw5rwWr/w2dDEuZsWAf UY7AvnlqxyTlZxAb72D2UeWLi1iDrxxfmHJHbVlRMpMKS4kjbsM6kTOAMtTGT6p8ga kq4FyN5hMPzjsU3uye/h6U1DzqDF+UPYFqUSOYcQ= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Hao Sun , Sean Christopherson , Paolo Bonzini Subject: [PATCH 5.4 061/244] KVM: Stop looking for coalesced MMIO zones if the bus is destroyed Date: Wed, 12 May 2021 16:47:12 +0200 Message-Id: <20210512144744.996554434@linuxfoundation.org> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20210512144743.039977287@linuxfoundation.org> References: <20210512144743.039977287@linuxfoundation.org> User-Agent: quilt/0.66 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Sean Christopherson commit 5d3c4c79384af06e3c8e25b7770b6247496b4417 upstream. Abort the walk of coalesced MMIO zones if kvm_io_bus_unregister_dev() fails to allocate memory for the new instance of the bus. If it can't instantiate a new bus, unregister_dev() destroys all devices _except_ the target device. But, it doesn't tell the caller that it obliterated the bus and invoked the destructor for all devices that were on the bus. In the coalesced MMIO case, this can result in a deleted list entry dereference due to attempting to continue iterating on coalesced_zones after future entries (in the walk) have been deleted. Opportunistically add curly braces to the for-loop, which encompasses many lines but sneaks by without braces due to the guts being a single if statement. Fixes: f65886606c2d ("KVM: fix memory leak in kvm_io_bus_unregister_dev()") Cc: stable@vger.kernel.org Reported-by: Hao Sun Signed-off-by: Sean Christopherson Message-Id: <20210412222050.876100-3-seanjc@google.com> Signed-off-by: Paolo Bonzini Signed-off-by: Greg Kroah-Hartman --- include/linux/kvm_host.h | 4 ++-- virt/kvm/coalesced_mmio.c | 19 +++++++++++++++++-- virt/kvm/kvm_main.c | 10 +++++----- 3 files changed, 24 insertions(+), 9 deletions(-) --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -192,8 +192,8 @@ int kvm_io_bus_read(struct kvm_vcpu *vcp int len, void *val); int kvm_io_bus_register_dev(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr, int len, struct kvm_io_device *dev); -void kvm_io_bus_unregister_dev(struct kvm *kvm, enum kvm_bus bus_idx, - struct kvm_io_device *dev); +int kvm_io_bus_unregister_dev(struct kvm *kvm, enum kvm_bus bus_idx, + struct kvm_io_device *dev); struct kvm_io_device *kvm_io_bus_get_dev(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr); --- a/virt/kvm/coalesced_mmio.c +++ b/virt/kvm/coalesced_mmio.c @@ -178,21 +178,36 @@ int kvm_vm_ioctl_unregister_coalesced_mm struct kvm_coalesced_mmio_zone *zone) { struct kvm_coalesced_mmio_dev *dev, *tmp; + int r; if (zone->pio != 1 && zone->pio != 0) return -EINVAL; mutex_lock(&kvm->slots_lock); - list_for_each_entry_safe(dev, tmp, &kvm->coalesced_zones, list) + list_for_each_entry_safe(dev, tmp, &kvm->coalesced_zones, list) { if (zone->pio == dev->zone.pio && coalesced_mmio_in_range(dev, zone->addr, zone->size)) { - kvm_io_bus_unregister_dev(kvm, + r = kvm_io_bus_unregister_dev(kvm, zone->pio ? KVM_PIO_BUS : KVM_MMIO_BUS, &dev->dev); kvm_iodevice_destructor(&dev->dev); + + /* + * On failure, unregister destroys all devices on the + * bus _except_ the target device, i.e. coalesced_zones + * has been modified. No need to restart the walk as + * there aren't any zones left. + */ + if (r) + break; } + } mutex_unlock(&kvm->slots_lock); + /* + * Ignore the result of kvm_io_bus_unregister_dev(), from userspace's + * perspective, the coalesced MMIO is most definitely unregistered. + */ return 0; } --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -4017,15 +4017,15 @@ int kvm_io_bus_register_dev(struct kvm * } /* Caller must hold slots_lock. */ -void kvm_io_bus_unregister_dev(struct kvm *kvm, enum kvm_bus bus_idx, - struct kvm_io_device *dev) +int kvm_io_bus_unregister_dev(struct kvm *kvm, enum kvm_bus bus_idx, + struct kvm_io_device *dev) { int i, j; struct kvm_io_bus *new_bus, *bus; bus = kvm_get_bus(kvm, bus_idx); if (!bus) - return; + return 0; for (i = 0; i < bus->dev_count; i++) if (bus->range[i].dev == dev) { @@ -4033,7 +4033,7 @@ void kvm_io_bus_unregister_dev(struct kv } if (i == bus->dev_count) - return; + return 0; new_bus = kmalloc(struct_size(bus, range, bus->dev_count - 1), GFP_KERNEL_ACCOUNT); @@ -4054,7 +4054,7 @@ 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; + return new_bus ? 0 : -ENOMEM; } struct kvm_io_device *kvm_io_bus_get_dev(struct kvm *kvm, enum kvm_bus bus_idx,