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

Commit 13b9f89b authored by Himateja Reddy's avatar Himateja Reddy Committed by Edgar Flores
Browse files

msm: adsprpc: protect access of context table



Add spin lock for accessing the context table to avoid
use after free in case of complete signal. Maintain subsystem
specific context table instead of global context table for
optimizing search performance.

Change-Id: I4df3a905a142048972ff5cdda3fdd93ee4c527bb
Acked-by: default avatarTadakamalla Krishnaiah <ktadakam@qti.qualcomm.com>
Signed-off-by: default avatarMohammed Nayeem Ur Rahman <mohara@codeaurora.org>
Signed-off-by: default avatarHimateja Reddy <hmreddy@codeaurora.org>
parent 5e3eb7b6
Loading
Loading
Loading
Loading
+54 −28
Original line number Diff line number Diff line
@@ -100,6 +100,13 @@
#define MDSP_DOMAIN_ID (1)
#define SDSP_DOMAIN_ID (2)
#define CDSP_DOMAIN_ID (3)

/*
 * ctxid of every message is OR-ed with fl->pd (0/1/2) before
 * it is sent to DSP. So mask 2 LSBs to retrieve actual context
 */
#define CONTEXT_PD_CHECK (3)

#define RH_CID ADSP_DOMAIN_ID

#define PERF_KEYS \
@@ -344,6 +351,8 @@ struct fastrpc_channel_ctx {
	/* cpu capabilities shared to DSP */
	uint64_t cpuinfo_todsp;
	bool cpuinfo_status;
	struct smq_invoke_ctx *ctxtable[FASTRPC_CTX_MAX];
	spinlock_t ctxlock;
};

struct fastrpc_apps {
@@ -360,8 +369,6 @@ struct fastrpc_apps {
	struct device *dev;
	unsigned int latency;
	int rpmsg_register;
	spinlock_t ctxlock;
	struct smq_invoke_ctx *ctxtable[FASTRPC_CTX_MAX];
	bool legacy_remote_heap;
	/* Unique job id for each message */
	uint64_t jobid[NUM_CHANNELS];
@@ -920,7 +927,7 @@ static int fastrpc_mmap_create(struct fastrpc_file *fl, int fd,
	int err = 0, vmid, sgl_index = 0;
	struct scatterlist *sgl = NULL;

	VERIFY(err, cid >= 0 && cid < NUM_CHANNELS);
	VERIFY(err, cid >= ADSP_DOMAIN_ID && cid < NUM_CHANNELS);
	if (err)
		goto bail;
	chan = &apps->channel[cid];
@@ -1314,11 +1321,12 @@ static int context_alloc(struct fastrpc_file *fl, uint32_t kernel,
			 struct smq_invoke_ctx **po)
{
	struct fastrpc_apps *me = &gfa;
	int err = 0, bufs, ii, size = 0;
	int err = 0, bufs, ii, size = 0, cid = fl->cid;
	struct smq_invoke_ctx *ctx = NULL;
	struct fastrpc_ctx_lst *clst = &fl->clst;
	struct fastrpc_ioctl_invoke *invoke = &invokefd->inv;
	int cid;
	struct fastrpc_channel_ctx *chan = NULL;
	unsigned long irq_flags = 0;

	bufs = REMOTE_SCALARS_LENGTH(invoke->sc);
	size = bufs * sizeof(*ctx->lpra) + bufs * sizeof(*ctx->maps) +
@@ -1382,17 +1390,18 @@ static int context_alloc(struct fastrpc_file *fl, uint32_t kernel,
	hlist_add_head(&ctx->hn, &clst->pending);
	spin_unlock(&fl->hlock);

	spin_lock(&me->ctxlock);
	cid = (fl->cid >= 0 && fl->cid < NUM_CHANNELS) ? fl->cid : 0;
	chan = &me->channel[cid];

	spin_lock_irqsave(&chan->ctxlock, irq_flags);
	me->jobid[cid]++;
	for (ii = 0; ii < FASTRPC_CTX_MAX; ii++) {
		if (!me->ctxtable[ii]) {
			me->ctxtable[ii] = ctx;
		if (!chan->ctxtable[ii]) {
			chan->ctxtable[ii] = ctx;
			ctx->ctxid = (me->jobid[cid] << 12) | (ii << 4);
			break;
		}
	}
	spin_unlock(&me->ctxlock);
	spin_unlock_irqrestore(&chan->ctxlock, irq_flags);
	VERIFY(err, ii < FASTRPC_CTX_MAX);
	if (err) {
		pr_err("adsprpc: out of context memory\n");
@@ -1423,15 +1432,18 @@ static void context_free(struct smq_invoke_ctx *ctx)
	struct fastrpc_apps *me = &gfa;
	int nbufs = REMOTE_SCALARS_INBUFS(ctx->sc) +
		    REMOTE_SCALARS_OUTBUFS(ctx->sc);
	int cid = ctx->fl->cid;
	struct fastrpc_channel_ctx *chan = &me->channel[cid];
	unsigned long irq_flags = 0;

	spin_lock(&me->ctxlock);
	spin_lock_irqsave(&chan->ctxlock, irq_flags);
	for (i = 0; i < FASTRPC_CTX_MAX; i++) {
		if (me->ctxtable[i] == ctx) {
			me->ctxtable[i] = NULL;
		if (chan->ctxtable[i] == ctx) {
			chan->ctxtable[i] = NULL;
			break;
		}
	}
	spin_unlock(&me->ctxlock);
	spin_unlock_irqrestore(&chan->ctxlock, irq_flags);

	spin_lock(&ctx->fl->hlock);
	hlist_del_init(&ctx->hn);
@@ -2097,7 +2109,6 @@ static void fastrpc_init(struct fastrpc_apps *me)
	INIT_HLIST_HEAD(&me->drivers);
	INIT_HLIST_HEAD(&me->maps);
	spin_lock_init(&me->hlock);
	spin_lock_init(&me->ctxlock);
	me->channel = &gcinfo[0];
	for (i = 0; i < NUM_CHANNELS; i++) {
		init_completion(&me->channel[i].work);
@@ -2107,6 +2118,7 @@ static void fastrpc_init(struct fastrpc_apps *me)
		me->channel[i].secure = SECURE_CHANNEL;
		mutex_init(&me->channel[i].smd_mutex);
		mutex_init(&me->channel[i].rpmsg_mutex);
		spin_lock_init(&me->channel[i].ctxlock);
	}
	/* Set CDSP channel to non secure */
	me->channel[CDSP_DOMAIN_ID].secure = NON_SECURE_CHANNEL;
@@ -2260,7 +2272,8 @@ static int fastrpc_internal_invoke(struct fastrpc_file *fl, uint32_t mode,
	int64_t *perf_counter = NULL;
	bool pm_awake_voted = false;

	VERIFY(err, cid >= 0 && cid < NUM_CHANNELS && fl->sctx != NULL);
	VERIFY(err, cid >= ADSP_DOMAIN_ID && cid < NUM_CHANNELS &&
		fl->sctx != NULL);
	if (err) {
		pr_err("adsprpc: ERROR: %s: kernel session not initialized yet for %s\n",
			__func__, current->comm);
@@ -2711,7 +2724,7 @@ static int fastrpc_send_cpuinfo_to_dsp(struct fastrpc_file *fl)
	struct fastrpc_ioctl_invoke_crc ioctl;
	remote_arg_t ra[2];

	VERIFY(err, fl && fl->cid >= 0 && fl->cid < NUM_CHANNELS);
	VERIFY(err, fl && fl->cid >= ADSP_DOMAIN_ID && fl->cid < NUM_CHANNELS);
	if (err)
		goto bail;

@@ -2887,7 +2900,7 @@ static int fastrpc_release_current_dsp_process(struct fastrpc_file *fl)
	remote_arg_t ra[1];
	int tgid = 0;

	VERIFY(err, fl->cid >= 0 && fl->cid < NUM_CHANNELS);
	VERIFY(err, fl->cid >= ADSP_DOMAIN_ID && fl->cid < NUM_CHANNELS);
	if (err)
		goto bail;
	VERIFY(err, fl->sctx != NULL);
@@ -3427,7 +3440,7 @@ static int fastrpc_rpmsg_probe(struct rpmsg_device *rpdev)
		return -EINVAL;

	cid = get_cid_from_rpdev(rpdev);
	VERIFY(err, cid >= 0 && cid < NUM_CHANNELS);
	VERIFY(err, cid >= ADSP_DOMAIN_ID && cid < NUM_CHANNELS);
	if (err)
		goto bail;
	mutex_lock(&gcinfo[cid].rpmsg_mutex);
@@ -3454,7 +3467,7 @@ static void fastrpc_rpmsg_remove(struct rpmsg_device *rpdev)
		return;

	cid = get_cid_from_rpdev(rpdev);
	VERIFY(err, cid >= 0 && cid < NUM_CHANNELS);
	VERIFY(err, cid >= ADSP_DOMAIN_ID && cid < NUM_CHANNELS);
	if (err)
		goto bail;
	mutex_lock(&gcinfo[cid].rpmsg_mutex);
@@ -3477,7 +3490,15 @@ static int fastrpc_rpmsg_callback(struct rpmsg_device *rpdev, void *data,
	struct fastrpc_apps *me = &gfa;
	uint32_t index, rsp_flags = 0, early_wake_time = 0;
	int err = 0, cid = -1;
	struct fastrpc_channel_ctx *chan = NULL;
	unsigned long irq_flags = 0;

	cid = get_cid_from_rpdev(rpdev);
	VERIFY(err, (cid >= ADSP_DOMAIN_ID && cid <= NUM_CHANNELS));
	if (err)
		goto bail;

	chan = &me->channel[cid];
	VERIFY(err, (rsp && len >= sizeof(*rsp)));
	if (err)
		goto bail;
@@ -3489,7 +3510,6 @@ static int fastrpc_rpmsg_callback(struct rpmsg_device *rpdev, void *data,
		early_wake_time = rspv2->early_wake_time;
		rsp_flags = rspv2->flags;
	}
	cid = get_cid_from_rpdev(rpdev);
	trace_fastrpc_rpmsg_response(cid, rsp->ctx,
		rsp->retval, rsp_flags, early_wake_time);

@@ -3498,26 +3518,32 @@ static int fastrpc_rpmsg_callback(struct rpmsg_device *rpdev, void *data,
	if (err)
		goto bail;

	VERIFY(err, !IS_ERR_OR_NULL(me->ctxtable[index]));
	spin_lock_irqsave(&chan->ctxlock, irq_flags);
	VERIFY(err, !IS_ERR_OR_NULL(chan->ctxtable[index]));
	if (err)
		goto bail;
		goto bail_unlock;

	VERIFY(err, ((me->ctxtable[index]->ctxid == (rsp->ctx & ~3)) &&
		me->ctxtable[index]->magic == FASTRPC_CTX_MAGIC));
	VERIFY(err, ((chan->ctxtable[index]->ctxid ==
		(rsp->ctx & ~CONTEXT_PD_CHECK)) &&
			chan->ctxtable[index]->magic ==
				FASTRPC_CTX_MAGIC));
	if (err)
		goto bail;
		goto bail_unlock;

	if (rspv2) {
		VERIFY(err, rspv2->version == FASTRPC_RSP_VERSION2);
		if (err)
			goto bail;
			goto bail_unlock;
	}
	context_notify_user(me->ctxtable[index], rsp->retval,
	context_notify_user(chan->ctxtable[index], rsp->retval,
				 rsp_flags, early_wake_time);
bail_unlock:
	spin_unlock_irqrestore(&chan->ctxlock, irq_flags);
bail:
	if (err)
		pr_err("adsprpc: ERROR: %s: invalid response (data %pK, len %d) from remote subsystem (err %d)\n",
				__func__, data, len, err);

	return err;
}