diff options
author | Gary King <gking@nvidia.com> | 2010-03-05 10:41:32 -0800 |
---|---|---|
committer | Gary King <gking@nvidia.com> | 2010-03-05 11:04:19 -0800 |
commit | e017a62d01aa6c7d0253b15182669295f000fa03 (patch) | |
tree | 19dc51fc6ce24c578f0bc9a8a3bf995428ea731f | |
parent | ded58bd5f0cab2bc6e4f0f5435422b6c0c23f6be (diff) |
[nvmap] handle NULL return for pin multiple, fix infinite loop
the handle alignment parameter query had an off-by-one bug in its
loop initializer which caused any carveout handle to trigger an
infinite loop. the only caller of this API was the debug EGL
driver, which used it to verify that the allocation matched
the requested alignment.
also, if the user passes NULL as the address array when pinning
multiple handles to ioctl_pinop, pin the handles and skip the
output write, rather than returning a permission error.
big thanks to antti for finding the infinite loop.
bug 660526
Change-Id: I90f819a231b5a8bef5b473252122cdbefc744efb
Reviewed-on: http://git-master/r/782
Reviewed-by: Gary King <gking@nvidia.com>
Tested-by: Gary King <gking@nvidia.com>
-rw-r--r-- | drivers/char/nvmap.c | 11 |
1 files changed, 7 insertions, 4 deletions
diff --git a/drivers/char/nvmap.c b/drivers/char/nvmap.c index 8546061016b6..c7f1cc44c5b6 100644 --- a/drivers/char/nvmap.c +++ b/drivers/char/nvmap.c @@ -1630,7 +1630,8 @@ static int nvmap_ioctl_pinop(struct file *filp, size_t bytes = op.count * sizeof(unsigned long *); if (!access_ok(VERIFY_READ, (void *)op.handles, bytes)) return -EPERM; - if (is_pin && !access_ok(VERIFY_WRITE, (void *)op.addr, bytes)) + if (is_pin && op.addr && + !access_ok(VERIFY_WRITE, (void *)op.addr, bytes)) return -EPERM; if (op.count <= ARRAY_SIZE(on_stack)) refs = on_stack; @@ -1662,6 +1663,8 @@ static int nvmap_ioctl_pinop(struct file *filp, output = (unsigned long __user *)&(tmp->addr); } + if (!output) goto out; + for (i=0; i<op.count; i++) { unsigned long addr; h = (struct nvmap_handle *)refs[i]; @@ -2479,15 +2482,15 @@ static unsigned int _nvmap_do_get_param(struct nvmap_handle *h, return h->orig_size; else if (param==NVMEM_HANDLE_PARAM_ALIGNMENT) { - unsigned int i = 0; - if (!h->alloc) return 0; if (h->heap_pgalloc) return PAGE_SIZE; else { + unsigned int i=1; + if (!h->carveout.base) return SZ_4M; while (!(i & h->carveout.base)) i<<=1; + return i; } - return i; } else if (param==NVMEM_HANDLE_PARAM_BASE) { WARN_ON(!h->alloc || !atomic_read(&h->pin)); |