diff options
author | Carter Cooper <ccooper@codeaurora.org> | 2018-01-17 09:49:00 -0700 |
---|---|---|
committer | samit vats <svats@codeaurora.org> | 2018-02-16 15:22:12 +0530 |
commit | 4ae2e3bd187b74b660a341f154ede9159d9301c8 (patch) | |
tree | 615a817503900b04df812f5b6f445ccbab180cd9 | |
parent | 38edeeedb5505a5d6148b8022ca2a5f9f3f4e5f6 (diff) |
msm: kgsl: Properly remove ref count on gpuobj_sync failure
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>
-rw-r--r-- | drivers/gpu/msm/kgsl.c | 34 |
1 files changed, 15 insertions, 19 deletions
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c index de4ba83903f9..294e9ac8dbc6 100644 --- a/drivers/gpu/msm/kgsl.c +++ b/drivers/gpu/msm/kgsl.c @@ -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); |