Commit 3b06ac67 authored by Juergen Gross's avatar Juergen Gross

xen/gntdev: replace global limit of mapped pages by limit per call

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 grant mappings is limited by the
hypervisor anyway and preferring kernel mappings over userspace ones
doesn't make sense. It should be noted that the gntdev device is
usable by root only.

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. This
per call limit (default: 65536 grant mappings) protects against
allocating insane large arrays in the kernel for doing a hypercall
which will fail anyway in case a user is e.g. trying to map billions
of pages.
Signed-off-by: default avatarJuergen Gross <jgross@suse.com>
Reviewed-by: default avatarOleksandr Andrushchenko <oleksandr_andrushchenko@epam.com>
Reviewed-by: default avatarBoris Ostrovsky <boris.ostrovsky@oracle.com>
Signed-off-by: default avatarJuergen Gross <jgross@suse.com>
parent d41b26d8
...@@ -81,7 +81,7 @@ void gntdev_add_map(struct gntdev_priv *priv, struct gntdev_grant_map *add); ...@@ -81,7 +81,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); 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); int gntdev_map_grant_pages(struct gntdev_grant_map *map);
......
...@@ -446,7 +446,7 @@ dmabuf_exp_alloc_backing_storage(struct gntdev_priv *priv, int dmabuf_flags, ...@@ -446,7 +446,7 @@ dmabuf_exp_alloc_backing_storage(struct gntdev_priv *priv, int dmabuf_flags,
{ {
struct gntdev_grant_map *map; struct gntdev_grant_map *map;
if (unlikely(count <= 0)) if (unlikely(gntdev_test_page_count(count)))
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
if ((dmabuf_flags & GNTDEV_DMA_FLAG_WC) && if ((dmabuf_flags & GNTDEV_DMA_FLAG_WC) &&
...@@ -459,11 +459,6 @@ dmabuf_exp_alloc_backing_storage(struct gntdev_priv *priv, int dmabuf_flags, ...@@ -459,11 +459,6 @@ dmabuf_exp_alloc_backing_storage(struct gntdev_priv *priv, int dmabuf_flags,
if (!map) if (!map)
return ERR_PTR(-ENOMEM); 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; return map;
} }
...@@ -771,7 +766,7 @@ long gntdev_ioctl_dmabuf_exp_from_refs(struct gntdev_priv *priv, int use_ptemod, ...@@ -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) if (copy_from_user(&op, u, sizeof(op)) != 0)
return -EFAULT; return -EFAULT;
if (unlikely(op.count <= 0)) if (unlikely(gntdev_test_page_count(op.count)))
return -EINVAL; return -EINVAL;
refs = kcalloc(op.count, sizeof(*refs), GFP_KERNEL); refs = kcalloc(op.count, sizeof(*refs), GFP_KERNEL);
...@@ -818,7 +813,7 @@ long gntdev_ioctl_dmabuf_imp_to_refs(struct gntdev_priv *priv, ...@@ -818,7 +813,7 @@ long gntdev_ioctl_dmabuf_imp_to_refs(struct gntdev_priv *priv,
if (copy_from_user(&op, u, sizeof(op)) != 0) if (copy_from_user(&op, u, sizeof(op)) != 0)
return -EFAULT; return -EFAULT;
if (unlikely(op.count <= 0)) if (unlikely(gntdev_test_page_count(op.count)))
return -EINVAL; return -EINVAL;
gntdev_dmabuf = dmabuf_imp_to_refs(priv->dmabuf_priv, gntdev_dmabuf = dmabuf_imp_to_refs(priv->dmabuf_priv,
......
...@@ -55,12 +55,10 @@ MODULE_AUTHOR("Derek G. Murray <Derek.Murray@cl.cam.ac.uk>, " ...@@ -55,12 +55,10 @@ MODULE_AUTHOR("Derek G. Murray <Derek.Murray@cl.cam.ac.uk>, "
"Gerd Hoffmann <kraxel@redhat.com>"); "Gerd Hoffmann <kraxel@redhat.com>");
MODULE_DESCRIPTION("User-space granted page access driver"); MODULE_DESCRIPTION("User-space granted page access driver");
static int limit = 1024*1024; static unsigned int limit = 64*1024;
module_param(limit, int, 0644); module_param(limit, uint, 0644);
MODULE_PARM_DESC(limit, "Maximum number of grants that may be mapped by " MODULE_PARM_DESC(limit,
"the gntdev device"); "Maximum number of grants that may be mapped by one mapping request");
static atomic_t pages_mapped = ATOMIC_INIT(0);
static int use_ptemod; static int use_ptemod;
...@@ -71,9 +69,9 @@ static struct miscdevice gntdev_miscdev; ...@@ -71,9 +69,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, static void gntdev_print_maps(struct gntdev_priv *priv,
...@@ -241,8 +239,6 @@ void gntdev_put_map(struct gntdev_priv *priv, struct gntdev_grant_map *map) ...@@ -241,8 +239,6 @@ void gntdev_put_map(struct gntdev_priv *priv, struct gntdev_grant_map *map)
if (!refcount_dec_and_test(&map->users)) if (!refcount_dec_and_test(&map->users))
return; return;
atomic_sub(map->count, &pages_mapped);
if (map->notify.flags & UNMAP_NOTIFY_SEND_EVENT) { if (map->notify.flags & UNMAP_NOTIFY_SEND_EVENT) {
notify_remote_via_evtchn(map->notify.event); notify_remote_via_evtchn(map->notify.event);
evtchn_put(map->notify.event); evtchn_put(map->notify.event);
...@@ -568,7 +564,7 @@ static long gntdev_ioctl_map_grant_ref(struct gntdev_priv *priv, ...@@ -568,7 +564,7 @@ static long gntdev_ioctl_map_grant_ref(struct gntdev_priv *priv,
if (copy_from_user(&op, u, sizeof(op)) != 0) if (copy_from_user(&op, u, sizeof(op)) != 0)
return -EFAULT; return -EFAULT;
pr_debug("priv %p, add %d\n", priv, op.count); 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; return -EINVAL;
err = -ENOMEM; err = -ENOMEM;
...@@ -576,12 +572,6 @@ static long gntdev_ioctl_map_grant_ref(struct gntdev_priv *priv, ...@@ -576,12 +572,6 @@ static long gntdev_ioctl_map_grant_ref(struct gntdev_priv *priv,
if (!map) if (!map)
return err; 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, if (copy_from_user(map->grants, &u->refs,
sizeof(map->grants[0]) * op.count) != 0) { sizeof(map->grants[0]) * op.count) != 0) {
gntdev_put_map(NULL, map); gntdev_put_map(NULL, map);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment