d6c48c0
From mboxrd@z Thu Jan  1 00:00:00 1970
d6c48c0
Return-Path: <SRS0=/BGd=SD=vger.kernel.org=linux-kernel-owner@kernel.org>
d6c48c0
X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on
d6c48c0
	aws-us-west-2-korg-lkml-1.web.codeaurora.org
d6c48c0
X-Spam-Level: 
d6c48c0
X-Spam-Status: No, score=-7.0 required=3.0 tests=HEADER_FROM_DIFFERENT_DOMAINS,
d6c48c0
	INCLUDES_PATCH,MAILING_LIST_MULTI,SIGNED_OFF_BY,SPF_PASS autolearn=ham
d6c48c0
	autolearn_force=no version=3.4.0
d6c48c0
Received: from mail.kernel.org (mail.kernel.org [198.145.29.99])
d6c48c0
	by smtp.lore.kernel.org (Postfix) with ESMTP id 5BCBAC43381
d6c48c0
	for <linux-kernel@archiver.kernel.org>; Mon,  1 Apr 2019 20:16:59 +0000 (UTC)
d6c48c0
Received: from vger.kernel.org (vger.kernel.org [209.132.180.67])
d6c48c0
	by mail.kernel.org (Postfix) with ESMTP id 31C4F20896
d6c48c0
	for <linux-kernel@archiver.kernel.org>; Mon,  1 Apr 2019 20:16:59 +0000 (UTC)
d6c48c0
Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand
d6c48c0
        id S1726867AbfDAUQ5 (ORCPT
d6c48c0
        <rfc822;linux-kernel@archiver.kernel.org>);
d6c48c0
        Mon, 1 Apr 2019 16:16:57 -0400
d6c48c0
Received: from mx1.redhat.com ([209.132.183.28]:52924 "EHLO mx1.redhat.com"
d6c48c0
        rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP
d6c48c0
        id S1726284AbfDAUQ5 (ORCPT <rfc822;linux-kernel@vger.kernel.org>);
d6c48c0
        Mon, 1 Apr 2019 16:16:57 -0400
d6c48c0
Received: from smtp.corp.redhat.com (int-mx07.intmail.prod.int.phx2.redhat.com [10.5.11.22])
d6c48c0
        (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits))
d6c48c0
        (No client certificate requested)
d6c48c0
        by mx1.redhat.com (Postfix) with ESMTPS id 6BC20307D933;
d6c48c0
        Mon,  1 Apr 2019 20:16:57 +0000 (UTC)
d6c48c0
Received: from gimli.home (ovpn-116-99.phx2.redhat.com [10.3.116.99])
d6c48c0
        by smtp.corp.redhat.com (Postfix) with ESMTP id AF2DC104C53F;
d6c48c0
        Mon,  1 Apr 2019 20:16:52 +0000 (UTC)
d6c48c0
Subject: [PATCH] vfio/type1: Limit DMA mappings per container
d6c48c0
From:   Alex Williamson <alex.williamson@redhat.com>
d6c48c0
To:     alex.williamson@redhat.com
d6c48c0
Cc:     kvm@vger.kernel.org, linux-kernel@vger.kernel.org,
d6c48c0
        eric.auger@redhat.com, cohuck@redhat.com
d6c48c0
Date:   Mon, 01 Apr 2019 14:16:52 -0600
d6c48c0
Message-ID: <155414977872.12780.13728555131525362206.stgit@gimli.home>
d6c48c0
User-Agent: StGit/0.19-dirty
d6c48c0
MIME-Version: 1.0
d6c48c0
Content-Type: text/plain; charset="utf-8"
d6c48c0
Content-Transfer-Encoding: 7bit
d6c48c0
X-Scanned-By: MIMEDefang 2.84 on 10.5.11.22
d6c48c0
X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.48]); Mon, 01 Apr 2019 20:16:57 +0000 (UTC)
d6c48c0
Sender: linux-kernel-owner@vger.kernel.org
d6c48c0
Precedence: bulk
d6c48c0
List-ID: <linux-kernel.vger.kernel.org>
d6c48c0
X-Mailing-List: linux-kernel@vger.kernel.org
d6c48c0
Archived-At: <https://lore.kernel.org/lkml/155414977872.12780.13728555131525362206.stgit@gimli.home/>
d6c48c0
List-Archive: <https://lore.kernel.org/lkml/>
d6c48c0
List-Post: <mailto:linux-kernel@vger.kernel.org>
d6c48c0
d6c48c0
Memory backed DMA mappings are accounted against a user's locked
d6c48c0
memory limit, including multiple mappings of the same memory.  This
d6c48c0
accounting bounds the number of such mappings that a user can create.
d6c48c0
However, DMA mappings that are not backed by memory, such as DMA
d6c48c0
mappings of device MMIO via mmaps, do not make use of page pinning
d6c48c0
and therefore do not count against the user's locked memory limit.
d6c48c0
These mappings still consume memory, but the memory is not well
d6c48c0
associated to the process for the purpose of oom killing a task.
d6c48c0
d6c48c0
To add bounding on this use case, we introduce a limit to the total
d6c48c0
number of concurrent DMA mappings that a user is allowed to create.
d6c48c0
This limit is exposed as a tunable module option where the default
d6c48c0
value of 64K is expected to be well in excess of any reasonable use
d6c48c0
case (a large virtual machine configuration would typically only make
d6c48c0
use of tens of concurrent mappings).
d6c48c0
d6c48c0
This fixes CVE-2019-3882.
d6c48c0
d6c48c0
Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
d6c48c0
---
d6c48c0
 drivers/vfio/vfio_iommu_type1.c |   14 ++++++++++++++
d6c48c0
 1 file changed, 14 insertions(+)
d6c48c0
d6c48c0
diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c
d6c48c0
index 73652e21efec..7fc8fd7d4dc7 100644
d6c48c0
--- a/drivers/vfio/vfio_iommu_type1.c
d6c48c0
+++ b/drivers/vfio/vfio_iommu_type1.c
d6c48c0
@@ -58,12 +58,18 @@ module_param_named(disable_hugepages,
d6c48c0
 MODULE_PARM_DESC(disable_hugepages,
d6c48c0
 		 "Disable VFIO IOMMU support for IOMMU hugepages.");
d6c48c0
 
d6c48c0
+static int dma_entry_limit __read_mostly = U16_MAX;
d6c48c0
+module_param_named(dma_entry_limit, dma_entry_limit, int, 0644);
d6c48c0
+MODULE_PARM_DESC(dma_entry_limit,
d6c48c0
+		 "Maximum number of user DMA mappings per container (65535).");
d6c48c0
+
d6c48c0
 struct vfio_iommu {
d6c48c0
 	struct list_head	domain_list;
d6c48c0
 	struct vfio_domain	*external_domain; /* domain for external user */
d6c48c0
 	struct mutex		lock;
d6c48c0
 	struct rb_root		dma_list;
d6c48c0
 	struct blocking_notifier_head notifier;
d6c48c0
+	atomic_t		dma_avail;
d6c48c0
 	bool			v2;
d6c48c0
 	bool			nesting;
d6c48c0
 };
d6c48c0
@@ -836,6 +842,7 @@ static void vfio_remove_dma(struct vfio_iommu *iommu, struct vfio_dma *dma)
d6c48c0
 	vfio_unlink_dma(iommu, dma);
d6c48c0
 	put_task_struct(dma->task);
d6c48c0
 	kfree(dma);
d6c48c0
+	atomic_inc(&iommu->dma_avail);
d6c48c0
 }
d6c48c0
 
d6c48c0
 static unsigned long vfio_pgsize_bitmap(struct vfio_iommu *iommu)
d6c48c0
@@ -1081,8 +1088,14 @@ static int vfio_dma_do_map(struct vfio_iommu *iommu,
d6c48c0
 		goto out_unlock;
d6c48c0
 	}
d6c48c0
 
d6c48c0
+	if (!atomic_add_unless(&iommu->dma_avail, -1, 0)) {
d6c48c0
+		ret = -ENOSPC;
d6c48c0
+		goto out_unlock;
d6c48c0
+	}
d6c48c0
+
d6c48c0
 	dma = kzalloc(sizeof(*dma), GFP_KERNEL);
d6c48c0
 	if (!dma) {
d6c48c0
+		atomic_inc(&iommu->dma_avail);
d6c48c0
 		ret = -ENOMEM;
d6c48c0
 		goto out_unlock;
d6c48c0
 	}
d6c48c0
@@ -1583,6 +1596,7 @@ static void *vfio_iommu_type1_open(unsigned long arg)
d6c48c0
 
d6c48c0
 	INIT_LIST_HEAD(&iommu->domain_list);
d6c48c0
 	iommu->dma_list = RB_ROOT;
d6c48c0
+	atomic_set(&iommu->dma_avail, dma_entry_limit);
d6c48c0
 	mutex_init(&iommu->lock);
d6c48c0
 	BLOCKING_INIT_NOTIFIER_HEAD(&iommu->notifier);
d6c48c0
 
d6c48c0
d6c48c0