Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a578ac96 authored by Puranam V G Tejaswi's avatar Puranam V G Tejaswi
Browse files

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: default avatarPuranam V G Tejaswi <pvgtejas@codeaurora.org>
parent 4cf5de75
Loading
Loading
Loading
Loading
+23 −4
Original line number Diff line number Diff line
@@ -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
+19 −4
Original line number Diff line number Diff line
@@ -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,12 +927,14 @@ 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);

	} else
		kmem_cache_free(jobs_cache, job);

	return 0;
}