diff options
author | Dan Carpenter <error27@gmail.com> | 2010-10-19 01:57:48 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2010-11-09 16:30:49 -0500 |
commit | e9f25689a86570c30d3f101b1f9834a579bed2e5 (patch) | |
tree | 1bfeb34fdeef5a2a1af5c0cb971c846fda15e4c4 | |
parent | bc704e31edc723a84c2469f26aa0279e1ddb948e (diff) |
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: Dan Carpenter <error27@gmail.com>
Acked-by: Vinod Koul <vinod.koul@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r-- | drivers/staging/intel_sst/intel_sst_app_interface.c | 93 |
1 files changed, 57 insertions, 36 deletions
diff --git a/drivers/staging/intel_sst/intel_sst_app_interface.c b/drivers/staging/intel_sst/intel_sst_app_interface.c index 8390aa793b7b..d20724d3b68d 100644 --- a/drivers/staging/intel_sst/intel_sst_app_interface.c +++ b/drivers/staging/intel_sst/intel_sst_app_interface.c | |||
@@ -1105,62 +1105,83 @@ long intel_sst_ioctl(struct file *file_ptr, unsigned int cmd, unsigned long arg) | |||
1105 | } | 1105 | } |
1106 | 1106 | ||
1107 | case _IOC_NR(SNDRV_SST_STREAM_DECODE): { | 1107 | case _IOC_NR(SNDRV_SST_STREAM_DECODE): { |
1108 | struct snd_sst_dbufs *param = | 1108 | struct snd_sst_dbufs param; |
1109 | (struct snd_sst_dbufs *)arg, dbufs_local; | 1109 | struct snd_sst_dbufs dbufs_local; |
1110 | int i; | ||
1111 | struct snd_sst_buffs ibufs, obufs; | 1110 | struct snd_sst_buffs ibufs, obufs; |
1112 | struct snd_sst_buff_entry ibuf_temp[param->ibufs->entries], | 1111 | struct snd_sst_buff_entry *ibuf_tmp, *obuf_tmp; |
1113 | obuf_temp[param->obufs->entries]; | 1112 | char __user *dest; |
1114 | 1113 | ||
1115 | pr_debug("sst: SNDRV_SST_STREAM_DECODE recived\n"); | 1114 | pr_debug("sst: SNDRV_SST_STREAM_DECODE recived\n"); |
1116 | if (minor != STREAM_MODULE) { | 1115 | if (minor != STREAM_MODULE) { |
1117 | retval = -EBADRQC; | 1116 | retval = -EBADRQC; |
1118 | break; | 1117 | break; |
1119 | } | 1118 | } |
1120 | if (!param) { | 1119 | if (copy_from_user(¶m, (void __user *)arg, |
1121 | retval = -EINVAL; | 1120 | sizeof(param))) { |
1121 | retval = -EFAULT; | ||
1122 | break; | 1122 | break; |
1123 | } | 1123 | } |
1124 | 1124 | ||
1125 | dbufs_local.input_bytes_consumed = param->input_bytes_consumed; | 1125 | dbufs_local.input_bytes_consumed = param.input_bytes_consumed; |
1126 | dbufs_local.output_bytes_produced = | 1126 | dbufs_local.output_bytes_produced = |
1127 | param->output_bytes_produced; | 1127 | param.output_bytes_produced; |
1128 | dbufs_local.ibufs = &ibufs; | 1128 | |
1129 | dbufs_local.obufs = &obufs; | 1129 | if (copy_from_user(&ibufs, param.ibufs, sizeof(ibufs))) { |
1130 | dbufs_local.ibufs->entries = param->ibufs->entries; | 1130 | retval = -EFAULT; |
1131 | dbufs_local.ibufs->type = param->ibufs->type; | 1131 | break; |
1132 | dbufs_local.obufs->entries = param->obufs->entries; | 1132 | } |
1133 | dbufs_local.obufs->type = param->obufs->type; | 1133 | if (copy_from_user(&obufs, param.obufs, sizeof(obufs))) { |
1134 | 1134 | retval = -EFAULT; | |
1135 | dbufs_local.ibufs->buff_entry = ibuf_temp; | 1135 | break; |
1136 | for (i = 0; i < dbufs_local.ibufs->entries; i++) { | 1136 | } |
1137 | ibuf_temp[i].buffer = | 1137 | |
1138 | param->ibufs->buff_entry[i].buffer; | 1138 | ibuf_tmp = kcalloc(ibufs.entries, sizeof(*ibuf_tmp), GFP_KERNEL); |
1139 | ibuf_temp[i].size = | 1139 | obuf_tmp = kcalloc(obufs.entries, sizeof(*obuf_tmp), GFP_KERNEL); |
1140 | param->ibufs->buff_entry[i].size; | 1140 | if (!ibuf_tmp || !obuf_tmp) { |
1141 | retval = -ENOMEM; | ||
1142 | goto free_iobufs; | ||
1143 | } | ||
1144 | |||
1145 | if (copy_from_user(ibuf_tmp, ibufs.buff_entry, | ||
1146 | ibufs.entries * sizeof(*ibuf_tmp))) { | ||
1147 | retval = -EFAULT; | ||
1148 | goto free_iobufs; | ||
1141 | } | 1149 | } |
1142 | dbufs_local.obufs->buff_entry = obuf_temp; | 1150 | ibufs.buff_entry = ibuf_tmp; |
1143 | for (i = 0; i < dbufs_local.obufs->entries; i++) { | 1151 | dbufs_local.ibufs = &ibufs; |
1144 | obuf_temp[i].buffer = | 1152 | |
1145 | param->obufs->buff_entry[i].buffer; | 1153 | if (copy_from_user(obuf_tmp, obufs.buff_entry, |
1146 | obuf_temp[i].size = | 1154 | obufs.entries * sizeof(*obuf_tmp))) { |
1147 | param->obufs->buff_entry[i].size; | 1155 | retval = -EFAULT; |
1156 | goto free_iobufs; | ||
1148 | } | 1157 | } |
1158 | obufs.buff_entry = obuf_tmp; | ||
1159 | dbufs_local.obufs = &obufs; | ||
1160 | |||
1149 | retval = sst_decode(str_id, &dbufs_local); | 1161 | retval = sst_decode(str_id, &dbufs_local); |
1150 | if (retval) | 1162 | if (retval) { |
1151 | retval = -EAGAIN; | 1163 | retval = -EAGAIN; |
1152 | if (copy_to_user(¶m->input_bytes_consumed, | 1164 | goto free_iobufs; |
1165 | } | ||
1166 | |||
1167 | dest = (char *)arg + offsetof(struct snd_sst_dbufs, input_bytes_consumed); | ||
1168 | if (copy_to_user(dest, | ||
1153 | &dbufs_local.input_bytes_consumed, | 1169 | &dbufs_local.input_bytes_consumed, |
1154 | sizeof(unsigned long long))) { | 1170 | sizeof(unsigned long long))) { |
1155 | retval = -EFAULT; | 1171 | retval = -EFAULT; |
1156 | break; | 1172 | goto free_iobufs; |
1157 | } | 1173 | } |
1158 | if (copy_to_user(¶m->output_bytes_produced, | 1174 | |
1175 | dest = (char *)arg + offsetof(struct snd_sst_dbufs, input_bytes_consumed); | ||
1176 | if (copy_to_user(dest, | ||
1159 | &dbufs_local.output_bytes_produced, | 1177 | &dbufs_local.output_bytes_produced, |
1160 | sizeof(unsigned long long))) { | 1178 | sizeof(unsigned long long))) { |
1161 | retval = -EFAULT; | 1179 | retval = -EFAULT; |
1162 | break; | 1180 | goto free_iobufs; |
1163 | } | 1181 | } |
1182 | free_iobufs: | ||
1183 | kfree(ibuf_tmp); | ||
1184 | kfree(obuf_tmp); | ||
1164 | break; | 1185 | break; |
1165 | } | 1186 | } |
1166 | 1187 | ||