aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDan Carpenter <error27@gmail.com>2010-10-19 01:57:48 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2010-11-09 16:30:49 -0500
commite9f25689a86570c30d3f101b1f9834a579bed2e5 (patch)
tree1bfeb34fdeef5a2a1af5c0cb971c846fda15e4c4
parentbc704e31edc723a84c2469f26aa0279e1ddb948e (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.c93
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(&param, (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(&param->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(&param->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 }
1182free_iobufs:
1183 kfree(ibuf_tmp);
1184 kfree(obuf_tmp);
1164 break; 1185 break;
1165 } 1186 }
1166 1187