diff options
author | Uday Kishore Pasupuleti <upasupul@codeaurora.org> | 2016-05-06 13:24:37 -0600 |
---|---|---|
committer | Devin Kim <dojip.kim@lge.com> | 2016-06-29 12:16:29 -0700 |
commit | c2222491fa15900ee525cc37d5595aa6d69aec31 (patch) | |
tree | 2b76e5e97b1f2139b0265ace60632f7047d692ea | |
parent | dc22be89e43bd0f7b224b29788c05d6b40b77bcd (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.c | 34 |
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; } |