Commit e9f25689 authored by Dan Carpenter's avatar Dan Carpenter Committed by Greg Kroah-Hartman

Staging: sst: fixups in SNDRV_SST_STREAM_DECODE

This is another patch about copying data to the kernel before using it.

SNDRV_SST_STREAM_DECODE is sort of tricky because we need to do a
copy_from_user() that gives us another two pointers and we have copy
those.  Those again give us some more pointers that we have to copy.

Besides those problems, the code had a stack overflow:
-	struct snd_sst_buff_entry ibuf_temp[param->ibufs->entries],
-		obuf_temp[param->obufs->entries];
param->ibufs->entries comes from the user.
Signed-off-by: default avatarDan Carpenter <error27@gmail.com>
Acked-by: default avatarVinod Koul <vinod.koul@intel.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent bc704e31
...@@ -1105,62 +1105,83 @@ long intel_sst_ioctl(struct file *file_ptr, unsigned int cmd, unsigned long arg) ...@@ -1105,62 +1105,83 @@ long intel_sst_ioctl(struct file *file_ptr, unsigned int cmd, unsigned long arg)
} }
case _IOC_NR(SNDRV_SST_STREAM_DECODE): { case _IOC_NR(SNDRV_SST_STREAM_DECODE): {
struct snd_sst_dbufs *param = struct snd_sst_dbufs param;
(struct snd_sst_dbufs *)arg, dbufs_local; struct snd_sst_dbufs dbufs_local;
int i;
struct snd_sst_buffs ibufs, obufs; struct snd_sst_buffs ibufs, obufs;
struct snd_sst_buff_entry ibuf_temp[param->ibufs->entries], struct snd_sst_buff_entry *ibuf_tmp, *obuf_tmp;
obuf_temp[param->obufs->entries]; char __user *dest;
pr_debug("sst: SNDRV_SST_STREAM_DECODE recived\n"); pr_debug("sst: SNDRV_SST_STREAM_DECODE recived\n");
if (minor != STREAM_MODULE) { if (minor != STREAM_MODULE) {
retval = -EBADRQC; retval = -EBADRQC;
break; break;
} }
if (!param) { if (copy_from_user(&param, (void __user *)arg,
retval = -EINVAL; sizeof(param))) {
retval = -EFAULT;
break; break;
} }
dbufs_local.input_bytes_consumed = param->input_bytes_consumed; dbufs_local.input_bytes_consumed = param.input_bytes_consumed;
dbufs_local.output_bytes_produced = dbufs_local.output_bytes_produced =
param->output_bytes_produced; param.output_bytes_produced;
dbufs_local.ibufs = &ibufs;
dbufs_local.obufs = &obufs; if (copy_from_user(&ibufs, param.ibufs, sizeof(ibufs))) {
dbufs_local.ibufs->entries = param->ibufs->entries; retval = -EFAULT;
dbufs_local.ibufs->type = param->ibufs->type; break;
dbufs_local.obufs->entries = param->obufs->entries; }
dbufs_local.obufs->type = param->obufs->type; if (copy_from_user(&obufs, param.obufs, sizeof(obufs))) {
retval = -EFAULT;
dbufs_local.ibufs->buff_entry = ibuf_temp; break;
for (i = 0; i < dbufs_local.ibufs->entries; i++) { }
ibuf_temp[i].buffer =
param->ibufs->buff_entry[i].buffer; ibuf_tmp = kcalloc(ibufs.entries, sizeof(*ibuf_tmp), GFP_KERNEL);
ibuf_temp[i].size = obuf_tmp = kcalloc(obufs.entries, sizeof(*obuf_tmp), GFP_KERNEL);
param->ibufs->buff_entry[i].size; if (!ibuf_tmp || !obuf_tmp) {
retval = -ENOMEM;
goto free_iobufs;
}
if (copy_from_user(ibuf_tmp, ibufs.buff_entry,
ibufs.entries * sizeof(*ibuf_tmp))) {
retval = -EFAULT;
goto free_iobufs;
} }
dbufs_local.obufs->buff_entry = obuf_temp; ibufs.buff_entry = ibuf_tmp;
for (i = 0; i < dbufs_local.obufs->entries; i++) { dbufs_local.ibufs = &ibufs;
obuf_temp[i].buffer =
param->obufs->buff_entry[i].buffer; if (copy_from_user(obuf_tmp, obufs.buff_entry,
obuf_temp[i].size = obufs.entries * sizeof(*obuf_tmp))) {
param->obufs->buff_entry[i].size; retval = -EFAULT;
goto free_iobufs;
} }
obufs.buff_entry = obuf_tmp;
dbufs_local.obufs = &obufs;
retval = sst_decode(str_id, &dbufs_local); retval = sst_decode(str_id, &dbufs_local);
if (retval) if (retval) {
retval = -EAGAIN; retval = -EAGAIN;
if (copy_to_user(&param->input_bytes_consumed, goto free_iobufs;
}
dest = (char *)arg + offsetof(struct snd_sst_dbufs, input_bytes_consumed);
if (copy_to_user(dest,
&dbufs_local.input_bytes_consumed, &dbufs_local.input_bytes_consumed,
sizeof(unsigned long long))) { sizeof(unsigned long long))) {
retval = -EFAULT; retval = -EFAULT;
break; goto free_iobufs;
} }
if (copy_to_user(&param->output_bytes_produced,
dest = (char *)arg + offsetof(struct snd_sst_dbufs, input_bytes_consumed);
if (copy_to_user(dest,
&dbufs_local.output_bytes_produced, &dbufs_local.output_bytes_produced,
sizeof(unsigned long long))) { sizeof(unsigned long long))) {
retval = -EFAULT; retval = -EFAULT;
break; goto free_iobufs;
} }
free_iobufs:
kfree(ibuf_tmp);
kfree(obuf_tmp);
break; break;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment