aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorUday Kishore Pasupuleti <upasupul@codeaurora.org>2016-05-06 13:24:37 -0600
committerDevin Kim <dojip.kim@lge.com>2016-06-29 12:16:29 -0700
commitc2222491fa15900ee525cc37d5595aa6d69aec31 (patch)
tree2b76e5e97b1f2139b0265ace60632f7047d692ea
parentdc22be89e43bd0f7b224b29788c05d6b40b77bcd (diff)
msm: kgsl: Avoid race condition in ioctl_syncsource_destroyandroid-wear-6.0.1_r0.55
If the ioctl syncsource_destroy is accessed by parallel threads, where the spinlock is acquired by threads after getting syncsource, then the simultaneous processes try to remove the already destroyed syncsource->refcount by the first thread that acquires this spinlock. This leads to race condition while removing syncsource->idr. Avoid separate lock inside getting syncsource, instead acquire spinlock before we get the syncsource in destroy ioctl so that the threads access the spinlock and operate on syncsource without use-after-free issue. Change-Id: I6add3800c40cd09f6e6e0cf2720e69059bd83cbc Signed-off-by: Divya Ponnusamy <pdivya@codeaurora.org> Signed-off-by: Uday Kishore Pasupuleti <upasupul@codeaurora.org>
-rw-r--r--drivers/gpu/msm/kgsl_sync.c34
1 files changed, 18 insertions, 16 deletions
diff --git a/drivers/gpu/msm/kgsl_sync.c b/drivers/gpu/msm/kgsl_sync.c
index b4097a7b986f..ef19d4303189 100644
--- a/drivers/gpu/msm/kgsl_sync.c
+++ b/drivers/gpu/msm/kgsl_sync.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2016, 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
@@ -402,19 +402,23 @@ long kgsl_ioctl_syncsource_create(struct kgsl_device_private *dev_priv,
goto out;
}
+ kref_init(&syncsource->refcount);
+ syncsource->private = private;
+
+ idr_preload(GFP_KERNEL);
mutex_lock(&private->process_private_mutex);
id = idr_alloc(&private->syncsource_idr, syncsource, 1, 0, GFP_KERNEL);
if (id > 0) {
- kref_init(&syncsource->refcount);
syncsource->id = id;
- syncsource->private = private;
-
param->id = id;
ret = 0;
} else {
ret = id;
}
+
mutex_unlock(&private->process_private_mutex);
+ idr_preload_end();
+
out:
if (ret) {
if (syncsource && syncsource->oneshot)
@@ -472,25 +476,23 @@ long kgsl_ioctl_syncsource_destroy(struct kgsl_device_private *dev_priv,
{
struct kgsl_syncsource_destroy *param = data;
struct kgsl_syncsource *syncsource = NULL;
- struct kgsl_process_private *private;
-
- syncsource = kgsl_syncsource_get(dev_priv->process_priv,
- param->id);
+ struct kgsl_process_private *private = dev_priv->process_priv;
- if (syncsource == NULL)
- return -EINVAL;
+ mutex_lock(&private->process_private_mutex);
+ syncsource = idr_find(&private->syncsource_idr, param->id);
- private = syncsource->private;
+ if (syncsource) {
+ idr_remove(&private->syncsource_idr, param->id);
+ syncsource->id = 0;
+ }
- mutex_lock(&private->process_private_mutex);
- idr_remove(&private->syncsource_idr, param->id);
- syncsource->id = 0;
mutex_unlock(&private->process_private_mutex);
+ if (syncsource == NULL)
+ return -EINVAL;
+
/* put reference from syncsource creation */
kgsl_syncsource_put(syncsource);
- /* put reference from getting the syncsource above */
- kgsl_syncsource_put(syncsource);
return 0;
}