ASoC: msm: acquire lock in ioctl

If two ioctls are triggered with different commands,
there is a possibility to access freed confidence level
memory. To resolve this acquire lock in ioctl.
Also release mutex lock properly in error cases.

CRs-Fixed: 1103085
Change-Id: I7d6b2eff21c8297e5f0755a0c141254be32f777d
Signed-off-by: Yeleswarapu Nagaradhesh <nagaradh@codeaurora.org>
This commit is contained in:
Yeleswarapu Nagaradhesh 2017-02-14 14:27:56 +05:30 committed by Divya Narayanan Poojary
parent 92529c25c5
commit 4ec8121178

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013-2016, Linux Foundation. All rights reserved.
* Copyright (c) 2013-2017, 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
@ -84,6 +84,7 @@ struct lsm_priv {
atomic_t buf_count;
atomic_t read_abort;
wait_queue_head_t period_wait;
struct mutex lsm_api_lock;
int appl_cnt;
int dma_write;
};
@ -869,10 +870,18 @@ static int msm_lsm_ioctl_shared(struct snd_pcm_substream *substream,
case SNDRV_LSM_EVENT_STATUS:
dev_dbg(rtd->dev, "%s: Get event status\n", __func__);
atomic_set(&prtd->event_wait_stop, 0);
/*
* Release the api lock before wait to allow
* other IOCTLs to be invoked while waiting
* for event
*/
mutex_unlock(&prtd->lsm_api_lock);
rc = wait_event_freezable(prtd->event_wait,
(cmpxchg(&prtd->event_avail, 1, 0) ||
(xchg = atomic_cmpxchg(&prtd->event_wait_stop,
1, 0))));
mutex_lock(&prtd->lsm_api_lock);
dev_dbg(rtd->dev, "%s: wait_event_freezable %d event_wait_stop %d\n",
__func__, rc, xchg);
if (!rc && !xchg) {
@ -1116,6 +1125,8 @@ static int msm_lsm_ioctl_compat(struct snd_pcm_substream *substream,
rtd = substream->private_data;
prtd = runtime->private_data;
mutex_lock(&prtd->lsm_api_lock);
switch (cmd) {
case SNDRV_LSM_EVENT_STATUS: {
struct snd_lsm_event_status *user = NULL, userarg32;
@ -1123,7 +1134,8 @@ static int msm_lsm_ioctl_compat(struct snd_pcm_substream *substream,
if (copy_from_user(&userarg32, arg, sizeof(userarg32))) {
dev_err(rtd->dev, "%s: err copyuser ioctl %s\n",
__func__, "SNDRV_LSM_EVENT_STATUS");
return -EFAULT;
err = -EFAULT;
goto done;
}
if (userarg32.payload_size >
@ -1131,7 +1143,8 @@ static int msm_lsm_ioctl_compat(struct snd_pcm_substream *substream,
pr_err("%s: payload_size %d is invalid, max allowed = %d\n",
__func__, userarg32.payload_size,
LISTEN_MAX_STATUS_PAYLOAD_SIZE);
return -EINVAL;
err = -EINVAL;
goto done;
}
size = sizeof(*user) + userarg32.payload_size;
@ -1140,7 +1153,8 @@ static int msm_lsm_ioctl_compat(struct snd_pcm_substream *substream,
dev_err(rtd->dev,
"%s: Allocation failed event status size %d\n",
__func__, size);
return -EFAULT;
err = -EFAULT;
goto done;
} else {
cmd = SNDRV_LSM_EVENT_STATUS;
user->payload_size = userarg32.payload_size;
@ -1189,7 +1203,8 @@ static int msm_lsm_ioctl_compat(struct snd_pcm_substream *substream,
dev_err(rtd->dev,
"%s: %s: not supported if using topology\n",
__func__, "REG_SND_MODEL_V2");
return -EINVAL;
err = -EINVAL;
goto done;
}
if (copy_from_user(&snd_modelv232, arg,
@ -1230,7 +1245,7 @@ static int msm_lsm_ioctl_compat(struct snd_pcm_substream *substream,
dev_err(rtd->dev,
"%s: %s: not supported if using topology\n",
__func__, "SET_PARAMS_32");
return -EINVAL;
err = -EINVAL;
}
if (copy_from_user(&det_params32, arg,
@ -1273,7 +1288,8 @@ static int msm_lsm_ioctl_compat(struct snd_pcm_substream *substream,
dev_err(rtd->dev,
"%s: %s: not supported if not using topology\n",
__func__, "SET_MODULE_PARAMS_32");
return -EINVAL;
err = -EINVAL;
goto done;
}
if (copy_from_user(&p_data_32, arg,
@ -1282,7 +1298,8 @@ static int msm_lsm_ioctl_compat(struct snd_pcm_substream *substream,
"%s: %s: copy_from_user failed, size = %zd\n",
__func__, "SET_MODULE_PARAMS_32",
sizeof(p_data_32));
return -EFAULT;
err = -EFAULT;
goto done;
}
p_data.params = compat_ptr(p_data_32.params);
@ -1294,7 +1311,8 @@ static int msm_lsm_ioctl_compat(struct snd_pcm_substream *substream,
"%s: %s: Invalid num_params %d\n",
__func__, "SET_MODULE_PARAMS_32",
p_data.num_params);
return -EINVAL;
err = -EINVAL;
goto done;
}
if (p_data.data_size !=
@ -1303,7 +1321,8 @@ static int msm_lsm_ioctl_compat(struct snd_pcm_substream *substream,
"%s: %s: Invalid size %d\n",
__func__, "SET_MODULE_PARAMS_32",
p_data.data_size);
return -EINVAL;
err = -EINVAL;
goto done;
}
p_size = sizeof(struct lsm_params_info_32) *
@ -1314,7 +1333,8 @@ static int msm_lsm_ioctl_compat(struct snd_pcm_substream *substream,
dev_err(rtd->dev,
"%s: no memory for params32, size = %zd\n",
__func__, p_size);
return -ENOMEM;
err = -ENOMEM;
goto done;
}
p_size = sizeof(struct lsm_params_info) * p_data.num_params;
@ -1324,7 +1344,8 @@ static int msm_lsm_ioctl_compat(struct snd_pcm_substream *substream,
"%s: no memory for params, size = %zd\n",
__func__, p_size);
kfree(params32);
return -ENOMEM;
err = -ENOMEM;
goto done;
}
if (copy_from_user(params32, p_data.params,
@ -1334,7 +1355,8 @@ static int msm_lsm_ioctl_compat(struct snd_pcm_substream *substream,
__func__, "params32", p_data.data_size);
kfree(params32);
kfree(params);
return -EFAULT;
err = -EFAULT;
goto done;
}
p_info_32 = (struct lsm_params_info_32 *) params32;
@ -1377,6 +1399,8 @@ static int msm_lsm_ioctl_compat(struct snd_pcm_substream *substream,
err = msm_lsm_ioctl_shared(substream, cmd, arg);
break;
}
done:
mutex_unlock(&prtd->lsm_api_lock);
return err;
}
#else
@ -1401,6 +1425,7 @@ static int msm_lsm_ioctl(struct snd_pcm_substream *substream,
prtd = runtime->private_data;
rtd = substream->private_data;
mutex_lock(&prtd->lsm_api_lock);
switch (cmd) {
case SNDRV_LSM_REG_SND_MODEL_V2: {
struct snd_lsm_sound_model_v2 snd_model_v2;
@ -1409,7 +1434,8 @@ static int msm_lsm_ioctl(struct snd_pcm_substream *substream,
dev_err(rtd->dev,
"%s: %s: not supported if using topology\n",
__func__, "REG_SND_MODEL_V2");
return -EINVAL;
err = -EINVAL;
goto done;
}
if (copy_from_user(&snd_model_v2, arg, sizeof(snd_model_v2))) {
@ -1436,7 +1462,8 @@ static int msm_lsm_ioctl(struct snd_pcm_substream *substream,
dev_err(rtd->dev,
"%s: %s: not supported if using topology\n",
__func__, "SET_PARAMS");
return -EINVAL;
err = -EINVAL;
goto done;
}
pr_debug("%s: SNDRV_LSM_SET_PARAMS\n", __func__);
@ -1457,7 +1484,8 @@ static int msm_lsm_ioctl(struct snd_pcm_substream *substream,
dev_err(rtd->dev,
"%s: LSM_SET_PARAMS failed, err %d\n",
__func__, err);
return err;
goto done;
}
case SNDRV_LSM_SET_MODULE_PARAMS: {
@ -1469,7 +1497,8 @@ static int msm_lsm_ioctl(struct snd_pcm_substream *substream,
dev_err(rtd->dev,
"%s: %s: not supported if not using topology\n",
__func__, "SET_MODULE_PARAMS");
return -EINVAL;
err = -EINVAL;
goto done;
}
if (copy_from_user(&p_data, arg,
@ -1477,7 +1506,8 @@ static int msm_lsm_ioctl(struct snd_pcm_substream *substream,
dev_err(rtd->dev,
"%s: %s: copy_from_user failed, size = %zd\n",
__func__, "p_data", sizeof(p_data));
return -EFAULT;
err = -EFAULT;
goto done;
}
if (p_data.num_params > LSM_PARAMS_MAX) {
@ -1485,7 +1515,8 @@ static int msm_lsm_ioctl(struct snd_pcm_substream *substream,
"%s: %s: Invalid num_params %d\n",
__func__, "SET_MODULE_PARAMS",
p_data.num_params);
return -EINVAL;
err = -EINVAL;
goto done;
}
p_size = p_data.num_params *
@ -1496,7 +1527,8 @@ static int msm_lsm_ioctl(struct snd_pcm_substream *substream,
"%s: %s: Invalid size %zd\n",
__func__, "SET_MODULE_PARAMS", p_size);
return -EFAULT;
err = -EFAULT;
goto done;
}
params = kzalloc(p_size, GFP_KERNEL);
@ -1504,7 +1536,8 @@ static int msm_lsm_ioctl(struct snd_pcm_substream *substream,
dev_err(rtd->dev,
"%s: no memory for params\n",
__func__);
return -ENOMEM;
err = -ENOMEM;
goto done;
}
if (copy_from_user(params, p_data.params,
@ -1513,7 +1546,8 @@ static int msm_lsm_ioctl(struct snd_pcm_substream *substream,
"%s: %s: copy_from_user failed, size = %d\n",
__func__, "params", p_data.data_size);
kfree(params);
return -EFAULT;
err = -EFAULT;
goto done;
}
err = msm_lsm_process_params(substream, &p_data, params);
@ -1533,7 +1567,8 @@ static int msm_lsm_ioctl(struct snd_pcm_substream *substream,
dev_err(rtd->dev,
"%s: err copyuser event_status\n",
__func__);
return -EFAULT;
err = -EFAULT;
goto done;
}
if (userarg.payload_size >
@ -1541,7 +1576,8 @@ static int msm_lsm_ioctl(struct snd_pcm_substream *substream,
pr_err("%s: payload_size %d is invalid, max allowed = %d\n",
__func__, userarg.payload_size,
LISTEN_MAX_STATUS_PAYLOAD_SIZE);
return -EINVAL;
err = -EINVAL;
goto done;
}
size = sizeof(struct snd_lsm_event_status) +
@ -1551,7 +1587,8 @@ static int msm_lsm_ioctl(struct snd_pcm_substream *substream,
dev_err(rtd->dev,
"%s: Allocation failed event status size %d\n",
__func__, size);
return -EFAULT;
err = -EFAULT;
goto done;
} else {
user->payload_size = userarg.payload_size;
err = msm_lsm_ioctl_shared(substream, cmd, user);
@ -1574,12 +1611,14 @@ static int msm_lsm_ioctl(struct snd_pcm_substream *substream,
if (err)
dev_err(rtd->dev,
"%s: lsmevent failed %d", __func__, err);
return err;
goto done;
}
default:
err = msm_lsm_ioctl_shared(substream, cmd, arg);
break;
}
done:
mutex_unlock(&prtd->lsm_api_lock);
return err;
}
@ -1596,6 +1635,7 @@ static int msm_lsm_open(struct snd_pcm_substream *substream)
__func__);
return -ENOMEM;
}
mutex_init(&prtd->lsm_api_lock);
spin_lock_init(&prtd->event_lock);
init_waitqueue_head(&prtd->event_wait);
init_waitqueue_head(&prtd->period_wait);
@ -1725,6 +1765,7 @@ static int msm_lsm_close(struct snd_pcm_substream *substream)
kfree(prtd->event_status);
prtd->event_status = NULL;
spin_unlock_irqrestore(&prtd->event_lock, flags);
mutex_destroy(&prtd->lsm_api_lock);
kfree(prtd);
runtime->private_data = NULL;