Received: by 2002:a05:6a10:16a7:0:0:0:0 with SMTP id gp39csp834040pxb; Tue, 3 Nov 2020 13:54:05 -0800 (PST) X-Google-Smtp-Source: ABdhPJy2Ze96Ucwgg8qYuGrcMqsV0UqLzr64oOBo3+gLuA1cEvSAI0TWD/DkZlr4TT+CAJTEQZBx X-Received: by 2002:a50:f316:: with SMTP id p22mr24341794edm.201.1604440444803; Tue, 03 Nov 2020 13:54:04 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1604440444; cv=none; d=google.com; s=arc-20160816; b=SFYFJdzMl+/6JvScH7QEx/7cJtMk9Awt2/dKUWfEjFAVL7ShF2/HxXzIAzSaKyJG3B j+UES4H3wdb6RoIb5CPvgXnZ2/Ma2yC9Pwj6csV8ECgzqIYOauKlEMnM0bKHpEt03KiU 5jee8wMelEx/9ghIDn9Dm6XlPnWhhCZKq/baIJlsbc1TM9tTXLW5R/jcLQRLQs+nXFON ZuFVtOz/jyD/vybV/X7h45nbJkaRxu0FuFCwwXaoR4LgCvOj4XoYBWBd1zI5JE+qtvrd 5kLrkrkOGrXixAqpMb48PlDFwia0KzelRZRPzs+MXgRNypaMBeKOn5CK0MRdAYUApH9k +7Qw== 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=GE47AT7gqyja4yqyibQ0FMKwRBbnU/uZr8RBYZBxWzI=; b=O2GMz6g1gKsPrC/NocCiToQ1Yme+NxFd4YwT9G2SgQCo+PRwcEWGzVvuu5wBNA8FNT ZbxMzlRomiqwzR+XiBLVc3fHYjbNRQx4Sf6pHSyisB3dwZ8jRQ9ZdYnG2EEvSWdthhZX D/ZQggQV27Ek0z8Yft9mYzprSYea9zwBLc9fvV8nA3dV0NgvH1sT8j7eTuDWYDWWTD4E 5WVdhVaUKPH/j/iBhgoWzmuk1MkvqfowNYLEVF+5eQdQyeiU8WGiJpJr3BJPSafgYo0D tD/8shkacmr53jGH1n6tBTE87xlwd3wc0zaXIt74ze/kRc1ImUzOHsEsMMjXo5+rYIsH GEwQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@kernel.org header.s=default header.b=LmLI4Z6K; 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=fail (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 p19si13557837edu.169.2020.11.03.13.53.41; Tue, 03 Nov 2020 13:54:04 -0800 (PST) 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=@kernel.org header.s=default header.b=LmLI4Z6K; 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=fail (p=NONE sp=NONE dis=NONE) header.from=linuxfoundation.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1731966AbgKCVvL (ORCPT + 99 others); Tue, 3 Nov 2020 16:51:11 -0500 Received: from mail.kernel.org ([198.145.29.99]:39902 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1730676AbgKCUs0 (ORCPT ); Tue, 3 Nov 2020 15:48:26 -0500 Received: from localhost (83-86-74-64.cable.dynamic.v4.ziggo.nl [83.86.74.64]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id 13B5822404; Tue, 3 Nov 2020 20:48:24 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=default; t=1604436505; bh=dqfSLO+/CBVVEPM5kB4ykciUWzIfWATuxS+Q0cNJzzs=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=LmLI4Z6Ky8mNV15Qe8S9w+xLfTyeqyV7dZtn1XduT1AzLmPE3gobLeAd5s9REyIzb D5WWkHveH2Buz+a40RPahePgTTeGYOrw6Ou5lxnjg5ZPkKH8Fw66lkirsvwLcGKp6g HsqM+jqHaWR7bSlIXubgg2iww7Hi6EEZCWmEhRFU= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, "Michael S. Tsirkin" Subject: [PATCH 5.9 262/391] Revert "vhost-vdpa: fix page pinning leakage in error path" Date: Tue, 3 Nov 2020 21:35:13 +0100 Message-Id: <20201103203404.702588488@linuxfoundation.org> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20201103203348.153465465@linuxfoundation.org> References: <20201103203348.153465465@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: Michael S. Tsirkin commit 5e1a3149eec8675c2767cc465903f5e4829de5b0 upstream. This reverts commit 7ed9e3d97c32d969caded2dfb6e67c1a2cc5a0b1. The patch creates a DoS risk since it can result in a high order memory allocation. Fixes: 7ed9e3d97c32d ("vhost-vdpa: fix page pinning leakage in error path") Cc: stable@vger.kernel.org Signed-off-by: Michael S. Tsirkin Signed-off-by: Greg Kroah-Hartman --- drivers/vhost/vdpa.c | 117 ++++++++++++++++++++------------------------------- 1 file changed, 47 insertions(+), 70 deletions(-) --- a/drivers/vhost/vdpa.c +++ b/drivers/vhost/vdpa.c @@ -595,19 +595,21 @@ static int vhost_vdpa_process_iotlb_upda struct vhost_dev *dev = &v->vdev; struct vhost_iotlb *iotlb = dev->iotlb; struct page **page_list; - struct vm_area_struct **vmas; + unsigned long list_size = PAGE_SIZE / sizeof(struct page *); unsigned int gup_flags = FOLL_LONGTERM; - unsigned long map_pfn, last_pfn = 0; - unsigned long npages, lock_limit; - unsigned long i, nmap = 0; + unsigned long npages, cur_base, map_pfn, last_pfn = 0; + unsigned long locked, lock_limit, pinned, i; u64 iova = msg->iova; - long pinned; int ret = 0; if (vhost_iotlb_itree_first(iotlb, msg->iova, msg->iova + msg->size - 1)) return -EEXIST; + page_list = (struct page **) __get_free_page(GFP_KERNEL); + if (!page_list) + return -ENOMEM; + if (msg->perm & VHOST_ACCESS_WO) gup_flags |= FOLL_WRITE; @@ -615,86 +617,61 @@ static int vhost_vdpa_process_iotlb_upda if (!npages) return -EINVAL; - page_list = kvmalloc_array(npages, sizeof(struct page *), GFP_KERNEL); - vmas = kvmalloc_array(npages, sizeof(struct vm_area_struct *), - GFP_KERNEL); - if (!page_list || !vmas) { - ret = -ENOMEM; - goto free; - } - mmap_read_lock(dev->mm); + locked = atomic64_add_return(npages, &dev->mm->pinned_vm); lock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT; - if (npages + atomic64_read(&dev->mm->pinned_vm) > lock_limit) { - ret = -ENOMEM; - goto unlock; - } - pinned = pin_user_pages(msg->uaddr & PAGE_MASK, npages, gup_flags, - page_list, vmas); - if (npages != pinned) { - if (pinned < 0) { - ret = pinned; - } else { - unpin_user_pages(page_list, pinned); - ret = -ENOMEM; - } - goto unlock; + if (locked > lock_limit) { + ret = -ENOMEM; + goto out; } + cur_base = msg->uaddr & PAGE_MASK; iova &= PAGE_MASK; - map_pfn = page_to_pfn(page_list[0]); - /* One more iteration to avoid extra vdpa_map() call out of loop. */ - for (i = 0; i <= npages; i++) { - unsigned long this_pfn; - u64 csize; - - /* The last chunk may have no valid PFN next to it */ - this_pfn = i < npages ? page_to_pfn(page_list[i]) : -1UL; - - if (last_pfn && (this_pfn == -1UL || - this_pfn != last_pfn + 1)) { - /* Pin a contiguous chunk of memory */ - csize = last_pfn - map_pfn + 1; - ret = vhost_vdpa_map(v, iova, csize << PAGE_SHIFT, - map_pfn << PAGE_SHIFT, - msg->perm); - if (ret) { - /* - * Unpin the rest chunks of memory on the - * flight with no corresponding vdpa_map() - * calls having been made yet. On the other - * hand, vdpa_unmap() in the failure path - * is in charge of accounting the number of - * pinned pages for its own. - * This asymmetrical pattern of accounting - * is for efficiency to pin all pages at - * once, while there is no other callsite - * of vdpa_map() than here above. - */ - unpin_user_pages(&page_list[nmap], - npages - nmap); - goto out; + while (npages) { + pinned = min_t(unsigned long, npages, list_size); + ret = pin_user_pages(cur_base, pinned, + gup_flags, page_list, NULL); + if (ret != pinned) + goto out; + + if (!last_pfn) + map_pfn = page_to_pfn(page_list[0]); + + for (i = 0; i < ret; i++) { + unsigned long this_pfn = page_to_pfn(page_list[i]); + u64 csize; + + if (last_pfn && (this_pfn != last_pfn + 1)) { + /* Pin a contiguous chunk of memory */ + csize = (last_pfn - map_pfn + 1) << PAGE_SHIFT; + if (vhost_vdpa_map(v, iova, csize, + map_pfn << PAGE_SHIFT, + msg->perm)) + goto out; + map_pfn = this_pfn; + iova += csize; } - atomic64_add(csize, &dev->mm->pinned_vm); - nmap += csize; - iova += csize << PAGE_SHIFT; - map_pfn = this_pfn; + + last_pfn = this_pfn; } - last_pfn = this_pfn; + + cur_base += ret << PAGE_SHIFT; + npages -= ret; } - WARN_ON(nmap != npages); + /* Pin the rest chunk */ + ret = vhost_vdpa_map(v, iova, (last_pfn - map_pfn + 1) << PAGE_SHIFT, + map_pfn << PAGE_SHIFT, msg->perm); out: - if (ret) + if (ret) { vhost_vdpa_unmap(v, msg->iova, msg->size); -unlock: + atomic64_sub(npages, &dev->mm->pinned_vm); + } mmap_read_unlock(dev->mm); -free: - kvfree(vmas); - kvfree(page_list); + free_page((unsigned long)page_list); return ret; }