video: tegra: nvmap: fix time-of-check,time-of-use vulnerability
Sri Krishna chowdary [Sat, 25 Feb 2017 19:02:47 +0000 (00:02 +0530)]
Validate the region specified by offset and size before performing
the operations like nvmap_prot_handle, nvmap_cache_maint and nvmap_handle_mk*.
This validation of offset and size once the values are in local variables
guarantees that even though user space changes the values in user buffers,
nvmap continues to perform operations with the contents that are validated.
Fixes Google Bug 34113000.

Bug 1862379
Bug 1880033

Change-Id: I32786d26c269a95122fbaf0b91d6d090cba7388e
Signed-off-by: Gagan Grover <ggrover@nvidia.com>
Reviewed-on: http://git-master/r/1298712
(cherry picked from commit f45441da608d8015ece73d253d4bdb48863f99e2)
Reviewed-on: http://git-master/r/1311631
(cherry picked from commit 22168ee3a52622c20ca8480de82102fb08119193)
Reviewed-on: http://git-master/r/1455425
Reviewed-by: Manish Tuteja <mtuteja@nvidia.com>
Tested-by: Manish Tuteja <mtuteja@nvidia.com>

drivers/video/tegra/nvmap/nvmap_cache.c
drivers/video/tegra/nvmap/nvmap_ioctl.c
drivers/video/tegra/nvmap/nvmap_mm.c
drivers/video/tegra/nvmap/nvmap_priv.h

index ccd8dd8..95f7d39 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * drivers/video/tegra/nvmap/nvmap_cache.c
  *
- * Copyright (c) 2011-2016, NVIDIA CORPORATION. All rights reserved.
+ * Copyright (c) 2011-2017, NVIDIA CORPORATION. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -312,6 +312,10 @@ int __nvmap_do_cache_maint(struct nvmap_client *client,
        h = nvmap_handle_get(h);
        if (!h)
                return -EFAULT;
+       if ((start >= h->size) || (end > h->size)) {
+               nvmap_handle_put(h);
+               return -EFAULT;
+       }
 
        nvmap_kmaps_inc(h);
        if (op == NVMAP_CACHE_OP_INV)
index 1eabbe9..f481a5a 100644 (file)
@@ -832,7 +832,7 @@ int nvmap_ioctl_cache_maint_list(struct file *filp, void __user *arg,
        if (copy_from_user(&op, arg, sizeof(op)))
                return -EFAULT;
 
-       if (!op.nr)
+       if (!op.nr || op.nr > UINT_MAX / sizeof(u32))
                return -EINVAL;
 
        if (!access_ok(VERIFY_READ, op.handles, op.nr * sizeof(u32)))
index 6dcf91a..d895cc4 100644 (file)
@@ -203,11 +203,13 @@ static int nvmap_prot_handle(struct nvmap_handle *handle, u32 offset,
        struct vm_area_struct *vma;
        int err = -EINVAL;
 
-       BUG_ON(offset);
-
        if (!handle->heap_pgalloc)
                return err;
 
+       if ((offset >= handle->size) || (offset > handle->size - size) ||
+           (size > handle->size))
+               return err;
+
        if (!size)
                size = handle->size;
 
@@ -349,15 +351,19 @@ int nvmap_reserve_pages(struct nvmap_handle **handles, u32 *offsets, u32 *sizes,
                return 0;
 
        if (op == NVMAP_PAGES_RESERVE) {
-               nvmap_do_cache_maint_list(handles, offsets, sizes,
+               err = nvmap_do_cache_maint_list(handles, offsets, sizes,
                                          NVMAP_CACHE_OP_WB, nr);
+               if (err)
+                       return err;
                for (i = 0; i < nr; i++)
                        nvmap_handle_mkclean(handles[i], offsets[i],
                                             sizes[i] ? sizes[i] : handles[i]->size);
        } else if ((op == NVMAP_PAGES_UNRESERVE) && handles[0]->heap_pgalloc) {
        } else {
-               nvmap_do_cache_maint_list(handles, offsets, sizes,
+               err = nvmap_do_cache_maint_list(handles, offsets, sizes,
                                          NVMAP_CACHE_OP_WB_INV, nr);
+               if (err)
+                       return err;
        }
        return 0;
 }
index b24e169..a57e6ad 100644 (file)
@@ -3,7 +3,7 @@
  *
  * GPU memory management driver for Tegra
  *
- * Copyright (c) 2009-2016, NVIDIA CORPORATION. All rights reserved.
+ * Copyright (c) 2009-2017, NVIDIA CORPORATION. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -513,12 +513,15 @@ static inline int nvmap_handle_mk(struct nvmap_handle *h,
                                  bool locked)
 {
        int i, nchanged = 0;
-       int start_page = PAGE_ALIGN(offset) >> PAGE_SHIFT;
-       int end_page = (offset + size) >> PAGE_SHIFT;
+       u32 start_page = PAGE_ALIGN(offset) >> PAGE_SHIFT;
+       u32 end_page = PAGE_ALIGN(offset + size) >> PAGE_SHIFT;
 
        if (!locked)
                mutex_lock(&h->lock);
-       if (h->heap_pgalloc) {
+       if (h->heap_pgalloc &&
+               (offset < h->size) &&
+               (size <= h->size) &&
+               (offset <= (h->size - size))) {
                for (i = start_page; i < end_page; i++)
                        nchanged += fn(&h->pgalloc.pages[i]) ? 1 : 0;
        }