From a578ac96d8e88e455397cdc77c6a4994ecf6c34b Mon Sep 17 00:00:00 2001 From: Puranam V G Tejaswi Date: Wed, 28 Oct 2020 02:46:28 +0530 Subject: [PATCH] msm: kgsl: Do not fail after drawobj is added to context queue After a drawobj is added to context drawqueue, if kmem_cache_alloc fails, we destroy the drawobj. This could lead to use-after-free if the context gets detached and drawobj is already destroyed meanwhile. Avoid this by doing allocation before the drawobj is added to the queue. Change-Id: I6d1f989b7795669f85756284db790f00f5fc2b9f Signed-off-by: Puranam V G Tejaswi --- drivers/gpu/msm/adreno_dispatch.c | 27 +++++++++++++++++++++++---- drivers/gpu/msm/adreno_hwsched.c | 23 +++++++++++++++++++---- 2 files changed, 42 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/msm/adreno_dispatch.c b/drivers/gpu/msm/adreno_dispatch.c index 31f7a2646755..aa50ae03efd2 100644 --- a/drivers/gpu/msm/adreno_dispatch.c +++ b/drivers/gpu/msm/adreno_dispatch.c @@ -1344,6 +1344,7 @@ int adreno_dispatcher_queue_cmds(struct kgsl_device_private *dev_priv, struct adreno_device *adreno_dev = ADRENO_DEVICE(device); struct adreno_context *drawctxt = ADRENO_CONTEXT(context); struct adreno_dispatcher_drawqueue *dispatch_q; + struct adreno_dispatch_job *job; int ret; unsigned int i, user_ts; @@ -1361,11 +1362,18 @@ int adreno_dispatcher_queue_cmds(struct kgsl_device_private *dev_priv, /* wait for the suspend gate */ wait_for_completion(&device->halt_gate); + job = kmem_cache_alloc(jobs_cache, GFP_KERNEL); + if (!job) + return -ENOMEM; + + job->drawctxt = drawctxt; + spin_lock(&drawctxt->lock); ret = _check_context_state_to_queue_cmds(drawctxt); if (ret) { spin_unlock(&drawctxt->lock); + kmem_cache_free(jobs_cache, job); return ret; } @@ -1383,6 +1391,7 @@ int adreno_dispatcher_queue_cmds(struct kgsl_device_private *dev_priv, */ if (timestamp_cmp(drawctxt->timestamp, user_ts) >= 0) { spin_unlock(&drawctxt->lock); + kmem_cache_free(jobs_cache, job); return -ERANGE; } } @@ -1393,8 +1402,10 @@ int adreno_dispatcher_queue_cmds(struct kgsl_device_private *dev_priv, case MARKEROBJ_TYPE: ret = drawctxt_queue_markerobj(adreno_dev, drawctxt, drawobj[i], timestamp, user_ts); - if (ret) + if (ret) { spin_unlock(&drawctxt->lock); + kmem_cache_free(jobs_cache, job); + } if (ret == 1) goto done; @@ -1406,6 +1417,7 @@ int adreno_dispatcher_queue_cmds(struct kgsl_device_private *dev_priv, drawobj[i], timestamp, user_ts); if (ret) { spin_unlock(&drawctxt->lock); + kmem_cache_free(jobs_cache, job); return ret; } break; @@ -1417,11 +1429,13 @@ int adreno_dispatcher_queue_cmds(struct kgsl_device_private *dev_priv, drawctxt, drawobj[i], timestamp, user_ts); if (ret) { spin_unlock(&drawctxt->lock); + kmem_cache_free(jobs_cache, job); return ret; } break; default: spin_unlock(&drawctxt->lock); + kmem_cache_free(jobs_cache, job); return -EINVAL; } @@ -1434,9 +1448,14 @@ int adreno_dispatcher_queue_cmds(struct kgsl_device_private *dev_priv, spin_unlock(&drawctxt->lock); /* Add the context to the dispatcher pending list */ - ret = dispatcher_queue_context(adreno_dev, drawctxt); - if (ret) - return ret; + if (_kgsl_context_get(&drawctxt->base)) { + trace_dispatch_queue_context(drawctxt); + llist_add(&job->node, + &adreno_dev->dispatcher.jobs[drawctxt->base.priority]); + } else { + kmem_cache_free(jobs_cache, job); + goto done; + } /* * Only issue commands if inflight is less than burst -this prevents us diff --git a/drivers/gpu/msm/adreno_hwsched.c b/drivers/gpu/msm/adreno_hwsched.c index 3cf94e2a5412..0648c6667764 100644 --- a/drivers/gpu/msm/adreno_hwsched.c +++ b/drivers/gpu/msm/adreno_hwsched.c @@ -832,6 +832,8 @@ int adreno_hwsched_queue_cmds(struct kgsl_device_private *dev_priv, struct kgsl_device *device = dev_priv->device; struct adreno_device *adreno_dev = ADRENO_DEVICE(device); struct adreno_context *drawctxt = ADRENO_CONTEXT(context); + struct adreno_hwsched *hwsched = to_hwsched(adreno_dev); + struct adreno_dispatch_job *job; int ret; unsigned int i, user_ts; @@ -866,11 +868,18 @@ int adreno_hwsched_queue_cmds(struct kgsl_device_private *dev_priv, /* wait for the suspend gate */ wait_for_completion(&device->halt_gate); + job = kmem_cache_alloc(jobs_cache, GFP_KERNEL); + if (!job) + return -ENOMEM; + + job->drawctxt = drawctxt; + spin_lock(&drawctxt->lock); ret = _check_context_state_to_queue_cmds(drawctxt); if (ret) { spin_unlock(&drawctxt->lock); + kmem_cache_free(jobs_cache, job); return ret; } @@ -885,9 +894,11 @@ int adreno_hwsched_queue_cmds(struct kgsl_device_private *dev_priv, timestamp, user_ts); if (ret == 1) { spin_unlock(&drawctxt->lock); + kmem_cache_free(jobs_cache, job); return 0; } else if (ret) { spin_unlock(&drawctxt->lock); + kmem_cache_free(jobs_cache, job); return ret; } break; @@ -897,6 +908,7 @@ int adreno_hwsched_queue_cmds(struct kgsl_device_private *dev_priv, timestamp, user_ts); if (ret) { spin_unlock(&drawctxt->lock); + kmem_cache_free(jobs_cache, job); return ret; } break; @@ -906,6 +918,7 @@ int adreno_hwsched_queue_cmds(struct kgsl_device_private *dev_priv, break; default: spin_unlock(&drawctxt->lock); + kmem_cache_free(jobs_cache, job); return -EINVAL; } @@ -914,11 +927,13 @@ int adreno_hwsched_queue_cmds(struct kgsl_device_private *dev_priv, spin_unlock(&drawctxt->lock); /* Add the context to the dispatcher pending list */ - ret = hwsched_queue_context(adreno_dev, drawctxt); - if (ret) - return ret; + if (_kgsl_context_get(&drawctxt->base)) { + trace_dispatch_queue_context(drawctxt); + llist_add(&job->node, &hwsched->jobs[drawctxt->base.priority]); + adreno_hwsched_issuecmds(adreno_dev); - adreno_hwsched_issuecmds(adreno_dev); + } else + kmem_cache_free(jobs_cache, job); return 0; }