video: tegra: nvmap: fix usermode input validation
Tuomas Tynkkynen [Tue, 31 Jul 2012 12:01:04 +0000 (15:01 +0300)]
nvmap_pin_ids accepts a list of handles to pin, which are passed
directly from usermode when called from nvmap_ioctl_pinop.

However, if invalid handles are passed in, the function might
still access them as valid handles, and cause a crash.

Bug 1023954

Change-Id: I6b98a2ef448bb496be7d569ddd4fb516fc399cba
Signed-off-by: Tuomas Tynkkynen <ttynkkynen@nvidia.com>
Reviewed-on: http://git-master/r/119667
Reviewed-by: Automatic_Commit_Validation_User
GVS: Gerrit_Virtual_Submit
Reviewed-by: Juha Tukkinen <jtukkinen@nvidia.com>
(cherry picked from commit 70d4ced2d12a1251202d67ffae7f5c0b3013cc94)
Reviewed-on: http://git-master/r/123478
Reviewed-by: Simone Willett <swillett@nvidia.com>
Tested-by: Simone Willett <swillett@nvidia.com>

drivers/video/tegra/nvmap/nvmap.c

index b7fd695..a0dcf26 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Memory manager for Tegra GPU
  *
- * Copyright (c) 2009-2011, NVIDIA Corporation.
+ * Copyright (c) 2009-2012, NVIDIA Corporation.
  *
  * 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
@@ -271,7 +271,7 @@ int nvmap_pin_ids(struct nvmap_client *client,
         * if the caller crashes after pinning a global handle, the handle
         * will be permanently leaked. */
        nvmap_ref_lock(client);
-       for (i = 0; i < nr && !ret; i++) {
+       for (i = 0; i < nr; i++) {
                ref = _nvmap_validate_id_locked(client, ids[i]);
                if (ref) {
                        atomic_inc(&ref->pin);
@@ -280,19 +280,19 @@ int nvmap_pin_ids(struct nvmap_client *client,
                        struct nvmap_handle *verify;
                        nvmap_ref_unlock(client);
                        verify = nvmap_validate_get(client, ids[i]);
-                       if (verify)
+                       if (verify) {
                                nvmap_warn(client, "%s pinning unreferenced "
                                           "handle %p\n",
                                           current->group_leader->comm, h[i]);
-                       else
+                       } else {
+                               h[i] = NULL;
                                ret = -EPERM;
+                       }
                        nvmap_ref_lock(client);
                }
        }
        nvmap_ref_unlock(client);
 
-       nr = i;
-
        if (ret)
                goto out;
 
@@ -317,6 +317,9 @@ out:
        if (ret) {
                nvmap_ref_lock(client);
                for (i = 0; i < nr; i++) {
+                       if(!ids[i])
+                               continue;
+
                        ref = _nvmap_validate_id_locked(client, ids[i]);
                        if (!ref) {
                                nvmap_warn(client, "%s freed handle %p "
@@ -330,7 +333,8 @@ out:
                nvmap_ref_unlock(client);
 
                for (i = 0; i < nr; i++)
-                       nvmap_handle_put(h[i]);
+                       if(h[i])
+                               nvmap_handle_put(h[i]);
        }
 
        return ret;