linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/2] xen/gntdev: sanitize user interface handling
@ 2019-07-18  6:52 Juergen Gross
  2019-07-18  6:52 ` [PATCH 1/2] xen/gntdev: replace global limit of mapped pages by limit per call Juergen Gross
                   ` (2 more replies)
  0 siblings, 3 replies; 6+ messages in thread
From: Juergen Gross @ 2019-07-18  6:52 UTC (permalink / raw)
  To: xen-devel, linux-kernel
  Cc: Juergen Gross, Boris Ostrovsky, Stefano Stabellini

The Xen gntdev driver's checking of the number of allowed mapped pages
is in need of some sanitizing work.

Juergen Gross (2):
  xen/gntdev: replace global limit of mapped pages by limit per call
  xen/gntdev: switch from kcalloc() to kvcalloc()

 drivers/xen/gntdev-common.h |  2 +-
 drivers/xen/gntdev-dmabuf.c | 11 +++-------
 drivers/xen/gntdev.c        | 52 ++++++++++++++++++---------------------------
 3 files changed, 25 insertions(+), 40 deletions(-)

-- 
2.16.4


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH 1/2] xen/gntdev: replace global limit of mapped pages by limit per call
  2019-07-18  6:52 [PATCH 0/2] xen/gntdev: sanitize user interface handling Juergen Gross
@ 2019-07-18  6:52 ` Juergen Gross
  2019-07-18 17:36   ` [Xen-devel] " Andrew Cooper
  2019-07-18  6:52 ` [PATCH 2/2] xen/gntdev: switch from kcalloc() to kvcalloc() Juergen Gross
  2019-07-18 10:00 ` [Xen-devel] [PATCH 0/2] xen/gntdev: sanitize user interface handling Oleksandr Andrushchenko
  2 siblings, 1 reply; 6+ messages in thread
From: Juergen Gross @ 2019-07-18  6:52 UTC (permalink / raw)
  To: xen-devel, linux-kernel
  Cc: Juergen Gross, Boris Ostrovsky, Stefano Stabellini

Today there is a global limit of pages mapped via /dev/xen/gntdev set
to 1 million pages per default. There is no reason why that limit is
existing, as total number of foreign mappings is limited by the
hypervisor anyway and preferring kernel mappings over userspace ones
doesn't make sense.

Additionally checking of that limit is fragile, as the number of pages
to map via one call is specified in a 32-bit unsigned variable which
isn't tested to stay within reasonable limits (the only test is the
value to be <= zero, which basically excludes only calls without any
mapping requested). So trying to map e.g. 0xffff0000 pages while
already nearly 1000000 pages are mapped will effectively lower the
global number of mapped pages such that a parallel call mapping a
reasonable amount of pages can succeed in spite of the global limit
being violated.

So drop the global limit and introduce per call limit instead.

Signed-off-by: Juergen Gross <jgross@suse.com>
---
 drivers/xen/gntdev-common.h |  2 +-
 drivers/xen/gntdev-dmabuf.c | 11 +++--------
 drivers/xen/gntdev.c        | 22 ++++++----------------
 3 files changed, 10 insertions(+), 25 deletions(-)

diff --git a/drivers/xen/gntdev-common.h b/drivers/xen/gntdev-common.h
index 2f8b949c3eeb..0e5d4660e7b8 100644
--- a/drivers/xen/gntdev-common.h
+++ b/drivers/xen/gntdev-common.h
@@ -87,7 +87,7 @@ void gntdev_add_map(struct gntdev_priv *priv, struct gntdev_grant_map *add);
 
 void gntdev_put_map(struct gntdev_priv *priv, struct gntdev_grant_map *map);
 
-bool gntdev_account_mapped_pages(int count);
+bool gntdev_test_page_count(unsigned int count);
 
 int gntdev_map_grant_pages(struct gntdev_grant_map *map);
 
diff --git a/drivers/xen/gntdev-dmabuf.c b/drivers/xen/gntdev-dmabuf.c
index 2c4f324f8626..63f0857bf62d 100644
--- a/drivers/xen/gntdev-dmabuf.c
+++ b/drivers/xen/gntdev-dmabuf.c
@@ -446,7 +446,7 @@ dmabuf_exp_alloc_backing_storage(struct gntdev_priv *priv, int dmabuf_flags,
 {
 	struct gntdev_grant_map *map;
 
-	if (unlikely(count <= 0))
+	if (unlikely(gntdev_test_page_count(count)))
 		return ERR_PTR(-EINVAL);
 
 	if ((dmabuf_flags & GNTDEV_DMA_FLAG_WC) &&
@@ -459,11 +459,6 @@ dmabuf_exp_alloc_backing_storage(struct gntdev_priv *priv, int dmabuf_flags,
 	if (!map)
 		return ERR_PTR(-ENOMEM);
 
-	if (unlikely(gntdev_account_mapped_pages(count))) {
-		pr_debug("can't map %d pages: over limit\n", count);
-		gntdev_put_map(NULL, map);
-		return ERR_PTR(-ENOMEM);
-	}
 	return map;
 }
 
@@ -771,7 +766,7 @@ long gntdev_ioctl_dmabuf_exp_from_refs(struct gntdev_priv *priv, int use_ptemod,
 	if (copy_from_user(&op, u, sizeof(op)) != 0)
 		return -EFAULT;
 
-	if (unlikely(op.count <= 0))
+	if (unlikely(gntdev_test_page_count(op.count)))
 		return -EINVAL;
 
 	refs = kcalloc(op.count, sizeof(*refs), GFP_KERNEL);
@@ -818,7 +813,7 @@ long gntdev_ioctl_dmabuf_imp_to_refs(struct gntdev_priv *priv,
 	if (copy_from_user(&op, u, sizeof(op)) != 0)
 		return -EFAULT;
 
-	if (unlikely(op.count <= 0))
+	if (unlikely(gntdev_test_page_count(op.count)))
 		return -EINVAL;
 
 	gntdev_dmabuf = dmabuf_imp_to_refs(priv->dmabuf_priv,
diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c
index 4c339c7e66e5..23e21a9aedf7 100644
--- a/drivers/xen/gntdev.c
+++ b/drivers/xen/gntdev.c
@@ -57,12 +57,10 @@ MODULE_AUTHOR("Derek G. Murray <Derek.Murray@cl.cam.ac.uk>, "
 	      "Gerd Hoffmann <kraxel@redhat.com>");
 MODULE_DESCRIPTION("User-space granted page access driver");
 
-static int limit = 1024*1024;
-module_param(limit, int, 0644);
+static unsigned int limit = 64*1024;
+module_param(limit, uint, 0644);
 MODULE_PARM_DESC(limit, "Maximum number of grants that may be mapped by "
-		"the gntdev device");
-
-static atomic_t pages_mapped = ATOMIC_INIT(0);
+		"one mapping request");
 
 static int use_ptemod;
 #define populate_freeable_maps use_ptemod
@@ -74,9 +72,9 @@ static struct miscdevice gntdev_miscdev;
 
 /* ------------------------------------------------------------------ */
 
-bool gntdev_account_mapped_pages(int count)
+bool gntdev_test_page_count(unsigned int count)
 {
-	return atomic_add_return(count, &pages_mapped) > limit;
+	return !count || count > limit;
 }
 
 static void gntdev_print_maps(struct gntdev_priv *priv,
@@ -244,8 +242,6 @@ void gntdev_put_map(struct gntdev_priv *priv, struct gntdev_grant_map *map)
 	if (!refcount_dec_and_test(&map->users))
 		return;
 
-	atomic_sub(map->count, &pages_mapped);
-
 	if (map->notify.flags & UNMAP_NOTIFY_SEND_EVENT) {
 		notify_remote_via_evtchn(map->notify.event);
 		evtchn_put(map->notify.event);
@@ -677,7 +673,7 @@ static long gntdev_ioctl_map_grant_ref(struct gntdev_priv *priv,
 	if (copy_from_user(&op, u, sizeof(op)) != 0)
 		return -EFAULT;
 	pr_debug("priv %p, add %d\n", priv, op.count);
-	if (unlikely(op.count <= 0))
+	if (unlikely(gntdev_test_page_count(op.count)))
 		return -EINVAL;
 
 	err = -ENOMEM;
@@ -685,12 +681,6 @@ static long gntdev_ioctl_map_grant_ref(struct gntdev_priv *priv,
 	if (!map)
 		return err;
 
-	if (unlikely(gntdev_account_mapped_pages(op.count))) {
-		pr_debug("can't map: over limit\n");
-		gntdev_put_map(NULL, map);
-		return err;
-	}
-
 	if (copy_from_user(map->grants, &u->refs,
 			   sizeof(map->grants[0]) * op.count) != 0) {
 		gntdev_put_map(NULL, map);
-- 
2.16.4


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 2/2] xen/gntdev: switch from kcalloc() to kvcalloc()
  2019-07-18  6:52 [PATCH 0/2] xen/gntdev: sanitize user interface handling Juergen Gross
  2019-07-18  6:52 ` [PATCH 1/2] xen/gntdev: replace global limit of mapped pages by limit per call Juergen Gross
@ 2019-07-18  6:52 ` Juergen Gross
  2019-07-18 10:00 ` [Xen-devel] [PATCH 0/2] xen/gntdev: sanitize user interface handling Oleksandr Andrushchenko
  2 siblings, 0 replies; 6+ messages in thread
From: Juergen Gross @ 2019-07-18  6:52 UTC (permalink / raw)
  To: xen-devel, linux-kernel
  Cc: Juergen Gross, Boris Ostrovsky, Stefano Stabellini

With sufficient many pages to map gntdev can reach order 9 allocation
sizes. As there is no need to have physically contiguous buffers switch
to kvcalloc() in order to avoid failing allocations.

Signed-off-by: Juergen Gross <jgross@suse.com>
---
 drivers/xen/gntdev.c | 30 +++++++++++++++---------------
 1 file changed, 15 insertions(+), 15 deletions(-)

diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c
index 23e21a9aedf7..961aa778312b 100644
--- a/drivers/xen/gntdev.c
+++ b/drivers/xen/gntdev.c
@@ -115,14 +115,14 @@ static void gntdev_free_map(struct gntdev_grant_map *map)
 		gnttab_free_pages(map->count, map->pages);
 
 #ifdef CONFIG_XEN_GRANT_DMA_ALLOC
-	kfree(map->frames);
+	kvfree(map->frames);
 #endif
-	kfree(map->pages);
-	kfree(map->grants);
-	kfree(map->map_ops);
-	kfree(map->unmap_ops);
-	kfree(map->kmap_ops);
-	kfree(map->kunmap_ops);
+	kvfree(map->pages);
+	kvfree(map->grants);
+	kvfree(map->map_ops);
+	kvfree(map->unmap_ops);
+	kvfree(map->kmap_ops);
+	kvfree(map->kunmap_ops);
 	kfree(map);
 }
 
@@ -136,12 +136,12 @@ struct gntdev_grant_map *gntdev_alloc_map(struct gntdev_priv *priv, int count,
 	if (NULL == add)
 		return NULL;
 
-	add->grants    = kcalloc(count, sizeof(add->grants[0]), GFP_KERNEL);
-	add->map_ops   = kcalloc(count, sizeof(add->map_ops[0]), GFP_KERNEL);
-	add->unmap_ops = kcalloc(count, sizeof(add->unmap_ops[0]), GFP_KERNEL);
-	add->kmap_ops  = kcalloc(count, sizeof(add->kmap_ops[0]), GFP_KERNEL);
-	add->kunmap_ops = kcalloc(count, sizeof(add->kunmap_ops[0]), GFP_KERNEL);
-	add->pages     = kcalloc(count, sizeof(add->pages[0]), GFP_KERNEL);
+	add->grants    = kvcalloc(count, sizeof(add->grants[0]), GFP_KERNEL);
+	add->map_ops   = kvcalloc(count, sizeof(add->map_ops[0]), GFP_KERNEL);
+	add->unmap_ops = kvcalloc(count, sizeof(add->unmap_ops[0]), GFP_KERNEL);
+	add->kmap_ops  = kvcalloc(count, sizeof(add->kmap_ops[0]), GFP_KERNEL);
+	add->kunmap_ops = kvcalloc(count, sizeof(add->kunmap_ops[0]), GFP_KERNEL);
+	add->pages     = kvcalloc(count, sizeof(add->pages[0]), GFP_KERNEL);
 	if (NULL == add->grants    ||
 	    NULL == add->map_ops   ||
 	    NULL == add->unmap_ops ||
@@ -160,8 +160,8 @@ struct gntdev_grant_map *gntdev_alloc_map(struct gntdev_priv *priv, int count,
 	if (dma_flags & (GNTDEV_DMA_FLAG_WC | GNTDEV_DMA_FLAG_COHERENT)) {
 		struct gnttab_dma_alloc_args args;
 
-		add->frames = kcalloc(count, sizeof(add->frames[0]),
-				      GFP_KERNEL);
+		add->frames = kvcalloc(count, sizeof(add->frames[0]),
+				       GFP_KERNEL);
 		if (!add->frames)
 			goto err;
 
-- 
2.16.4


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [Xen-devel] [PATCH 0/2] xen/gntdev: sanitize user interface handling
  2019-07-18  6:52 [PATCH 0/2] xen/gntdev: sanitize user interface handling Juergen Gross
  2019-07-18  6:52 ` [PATCH 1/2] xen/gntdev: replace global limit of mapped pages by limit per call Juergen Gross
  2019-07-18  6:52 ` [PATCH 2/2] xen/gntdev: switch from kcalloc() to kvcalloc() Juergen Gross
@ 2019-07-18 10:00 ` Oleksandr Andrushchenko
  2 siblings, 0 replies; 6+ messages in thread
From: Oleksandr Andrushchenko @ 2019-07-18 10:00 UTC (permalink / raw)
  To: Juergen Gross, xen-devel, linux-kernel
  Cc: Boris Ostrovsky, Stefano Stabellini

On 7/18/19 9:52 AM, Juergen Gross wrote:
> The Xen gntdev driver's checking of the number of allowed mapped pages
> is in need of some sanitizing work.
>
> Juergen Gross (2):
>    xen/gntdev: replace global limit of mapped pages by limit per call
>    xen/gntdev: switch from kcalloc() to kvcalloc()
>
>   drivers/xen/gntdev-common.h |  2 +-
>   drivers/xen/gntdev-dmabuf.c | 11 +++-------
>   drivers/xen/gntdev.c        | 52 ++++++++++++++++++---------------------------
>   3 files changed, 25 insertions(+), 40 deletions(-)
>
For the series:
Reviewed-by: Oleksandr Andrushchenko <oleksandr_andrushchenko@epam.com>

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [Xen-devel] [PATCH 1/2] xen/gntdev: replace global limit of mapped pages by limit per call
  2019-07-18  6:52 ` [PATCH 1/2] xen/gntdev: replace global limit of mapped pages by limit per call Juergen Gross
@ 2019-07-18 17:36   ` Andrew Cooper
  2019-07-19  4:06     ` Juergen Gross
  0 siblings, 1 reply; 6+ messages in thread
From: Andrew Cooper @ 2019-07-18 17:36 UTC (permalink / raw)
  To: Juergen Gross, xen-devel, linux-kernel
  Cc: Boris Ostrovsky, Stefano Stabellini

On 18/07/2019 07:52, Juergen Gross wrote:
> Today there is a global limit of pages mapped via /dev/xen/gntdev set
> to 1 million pages per default.

The Xen default limit even for dom0 is 1024 pages * 16 entries per page,
which is far lower than this limit.

> There is no reason why that limit is
> existing, as total number of foreign mappings is limited by the

s/foreign/grant/ ?

> hypervisor anyway and preferring kernel mappings over userspace ones
> doesn't make sense.

Its probably also worth stating that this a root-only device, which
further brings in to question the user/kernel split.

>
> Additionally checking of that limit is fragile, as the number of pages
> to map via one call is specified in a 32-bit unsigned variable which
> isn't tested to stay within reasonable limits (the only test is the
> value to be <= zero, which basically excludes only calls without any
> mapping requested). So trying to map e.g. 0xffff0000 pages while
> already nearly 1000000 pages are mapped will effectively lower the
> global number of mapped pages such that a parallel call mapping a
> reasonable amount of pages can succeed in spite of the global limit
> being violated.
>
> So drop the global limit and introduce per call limit instead.

Its probably worth talking about this new limit.  What is it trying to
protect?

~Andrew

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [Xen-devel] [PATCH 1/2] xen/gntdev: replace global limit of mapped pages by limit per call
  2019-07-18 17:36   ` [Xen-devel] " Andrew Cooper
@ 2019-07-19  4:06     ` Juergen Gross
  0 siblings, 0 replies; 6+ messages in thread
From: Juergen Gross @ 2019-07-19  4:06 UTC (permalink / raw)
  To: Andrew Cooper, xen-devel, linux-kernel
  Cc: Stefano Stabellini, Boris Ostrovsky

On 18.07.19 19:36, Andrew Cooper wrote:
> On 18/07/2019 07:52, Juergen Gross wrote:
>> Today there is a global limit of pages mapped via /dev/xen/gntdev set
>> to 1 million pages per default.
> 
> The Xen default limit even for dom0 is 1024 pages * 16 entries per page,
> which is far lower than this limit.

Actually its 256 entries per page, but this is still lower than the
current limit.

> 
>> There is no reason why that limit is
>> existing, as total number of foreign mappings is limited by the
> 
> s/foreign/grant/ ?

Can do.

> 
>> hypervisor anyway and preferring kernel mappings over userspace ones
>> doesn't make sense.
> 
> Its probably also worth stating that this a root-only device, which
> further brings in to question the user/kernel split.

Yes.

> 
>>
>> Additionally checking of that limit is fragile, as the number of pages
>> to map via one call is specified in a 32-bit unsigned variable which
>> isn't tested to stay within reasonable limits (the only test is the
>> value to be <= zero, which basically excludes only calls without any
>> mapping requested). So trying to map e.g. 0xffff0000 pages while
>> already nearly 1000000 pages are mapped will effectively lower the
>> global number of mapped pages such that a parallel call mapping a
>> reasonable amount of pages can succeed in spite of the global limit
>> being violated.
>>
>> So drop the global limit and introduce per call limit instead.
> 
> Its probably worth talking about this new limit.  What is it trying to
> protect?

Out-of-bounds allocations.


Juergen

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2019-07-19  4:28 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-07-18  6:52 [PATCH 0/2] xen/gntdev: sanitize user interface handling Juergen Gross
2019-07-18  6:52 ` [PATCH 1/2] xen/gntdev: replace global limit of mapped pages by limit per call Juergen Gross
2019-07-18 17:36   ` [Xen-devel] " Andrew Cooper
2019-07-19  4:06     ` Juergen Gross
2019-07-18  6:52 ` [PATCH 2/2] xen/gntdev: switch from kcalloc() to kvcalloc() Juergen Gross
2019-07-18 10:00 ` [Xen-devel] [PATCH 0/2] xen/gntdev: sanitize user interface handling Oleksandr Andrushchenko

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).