OSDN Git Service

msm: kgsl: Properly remove ref count on gpuobj_sync failure
authorCarter Cooper <ccooper@codeaurora.org>
Wed, 17 Jan 2018 16:49:00 +0000 (09:49 -0700)
committersamit vats <svats@codeaurora.org>
Fri, 16 Feb 2018 09:52:12 +0000 (15:22 +0530)
The user can pass bad data into kgsl_ioctl_gpuobj_sync(). If
_copy_from_user() fails do to bad data, undo any current
references taken through this ioctl call.

Change-Id: I56195520b9dadba20ee419658fc2cbb282b8449c
Signed-off-by: Carter Cooper <ccooper@codeaurora.org>
Signed-off-by: samit vats <svats@codeaurora.org>
drivers/gpu/msm/kgsl.c

index de4ba83..294e9ac 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2008-2018, The Linux Foundation. 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 version 2 and
@@ -2943,7 +2943,7 @@ long kgsl_ioctl_gpuobj_sync(struct kgsl_device_private *dev_priv,
        long ret = 0;
        bool full_flush = false;
        uint64_t size = 0;
-       int i, count = 0;
+       int i;
        void __user *ptr;
 
        if (param->count == 0 || param->count > 128)
@@ -2955,8 +2955,8 @@ long kgsl_ioctl_gpuobj_sync(struct kgsl_device_private *dev_priv,
 
        entries = kzalloc(param->count * sizeof(*entries), GFP_KERNEL);
        if (entries == NULL) {
-               ret = -ENOMEM;
-               goto out;
+               kfree(objs);
+               return -ENOMEM;
        }
 
        ptr = to_user_ptr(param->objs);
@@ -2973,36 +2973,32 @@ long kgsl_ioctl_gpuobj_sync(struct kgsl_device_private *dev_priv,
                if (entries[i] == NULL)
                        continue;
 
-               count++;
-
                if (!(objs[i].op & KGSL_GPUMEM_CACHE_RANGE))
                        size += entries[i]->memdesc.size;
                else if (objs[i].offset < entries[i]->memdesc.size)
                        size += (entries[i]->memdesc.size - objs[i].offset);
 
                full_flush = check_full_flush(size, objs[i].op);
-               if (full_flush)
-                       break;
+               if (full_flush) {
+                       trace_kgsl_mem_sync_full_cache(i, size);
+                       flush_cache_all();
+                       goto out;
+               }
 
                ptr += sizeof(*objs);
        }
 
-       if (full_flush) {
-               trace_kgsl_mem_sync_full_cache(count, size);
-               flush_cache_all();
-       } else {
-               for (i = 0; !ret && i < param->count; i++)
-                       if (entries[i])
-                               ret = _kgsl_gpumem_sync_cache(entries[i],
-                                               objs[i].offset, objs[i].length,
-                                               objs[i].op);
-       }
+       for (i = 0; !ret && i < param->count; i++)
+               if (entries[i])
+                       ret = _kgsl_gpumem_sync_cache(entries[i],
+                                       objs[i].offset, objs[i].length,
+                                       objs[i].op);
 
+out:
        for (i = 0; i < param->count; i++)
                if (entries[i])
                        kgsl_mem_entry_put(entries[i]);
 
-out:
        kfree(entries);
        kfree(objs);