aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2010-04-13 05:33:54 -0400
committerTakashi Iwai <tiwai@suse.de>2010-04-13 06:01:14 -0400
commitd97e1b78239c7e7e441088e0b644bd3b076002e6 (patch)
treeb05b5085bea932662ce60061d5b4b93834683327
parent24e4a1211f691fc671de44685430dbad757d8487 (diff)
ALSA: info - Check file position validity in common layer
Check the validity of the file position in the common info layer before calling read or write callbacks in assumption that entry->size is set up properly to indicate the max file size. Removed the redundant checks from the callbacks as well. Signed-off-by: Takashi Iwai <tiwai@suse.de>
-rw-r--r--sound/core/info.c14
-rw-r--r--sound/drivers/opl4/opl4_proc.c46
-rw-r--r--sound/isa/gus/gus_mem_proc.c14
-rw-r--r--sound/pci/cs4281.c24
-rw-r--r--sound/pci/cs46xx/cs46xx_lib.c12
-rw-r--r--sound/pci/emu10k1/emuproc.c43
-rw-r--r--sound/pci/mixart/mixart.c12
7 files changed, 60 insertions, 105 deletions
diff --git a/sound/core/info.c b/sound/core/info.c
index ff968be81678..f90a6fd43fb4 100644
--- a/sound/core/info.c
+++ b/sound/core/info.c
@@ -232,10 +232,15 @@ static ssize_t snd_info_entry_read(struct file *file, char __user *buffer,
232 return -EFAULT; 232 return -EFAULT;
233 break; 233 break;
234 case SNDRV_INFO_CONTENT_DATA: 234 case SNDRV_INFO_CONTENT_DATA:
235 if (entry->c.ops->read) 235 if (pos >= entry->size)
236 return 0;
237 if (entry->c.ops->read) {
238 size = entry->size - pos;
239 size = min(count, size);
236 size = entry->c.ops->read(entry, 240 size = entry->c.ops->read(entry,
237 data->file_private_data, 241 data->file_private_data,
238 file, buffer, count, pos); 242 file, buffer, size, pos);
243 }
239 break; 244 break;
240 } 245 }
241 if ((ssize_t) size > 0) 246 if ((ssize_t) size > 0)
@@ -282,10 +287,13 @@ static ssize_t snd_info_entry_write(struct file *file, const char __user *buffer
282 size = count; 287 size = count;
283 break; 288 break;
284 case SNDRV_INFO_CONTENT_DATA: 289 case SNDRV_INFO_CONTENT_DATA:
285 if (entry->c.ops->write) 290 if (entry->c.ops->write && count > 0) {
291 size_t maxsize = entry->size - pos;
292 count = min(count, maxsize);
286 size = entry->c.ops->write(entry, 293 size = entry->c.ops->write(entry,
287 data->file_private_data, 294 data->file_private_data,
288 file, buffer, count, pos); 295 file, buffer, count, pos);
296 }
289 break; 297 break;
290 } 298 }
291 if ((ssize_t) size > 0) 299 if ((ssize_t) size > 0)
diff --git a/sound/drivers/opl4/opl4_proc.c b/sound/drivers/opl4/opl4_proc.c
index eb72814dfd5f..210b89de06d7 100644
--- a/sound/drivers/opl4/opl4_proc.c
+++ b/sound/drivers/opl4/opl4_proc.c
@@ -55,25 +55,18 @@ static ssize_t snd_opl4_mem_proc_read(struct snd_info_entry *entry,
55 size_t count, loff_t pos) 55 size_t count, loff_t pos)
56{ 56{
57 struct snd_opl4 *opl4 = entry->private_data; 57 struct snd_opl4 *opl4 = entry->private_data;
58 long size;
59 char* buf; 58 char* buf;
60 59
61 size = count; 60 buf = vmalloc(count);
62 if (pos + size > entry->size) 61 if (!buf)
63 size = entry->size - pos; 62 return -ENOMEM;
64 if (size > 0) { 63 snd_opl4_read_memory(opl4, buf, pos, count);
65 buf = vmalloc(size); 64 if (copy_to_user(_buf, buf, count)) {
66 if (!buf)
67 return -ENOMEM;
68 snd_opl4_read_memory(opl4, buf, pos, size);
69 if (copy_to_user(_buf, buf, size)) {
70 vfree(buf);
71 return -EFAULT;
72 }
73 vfree(buf); 65 vfree(buf);
74 return size; 66 return -EFAULT;
75 } 67 }
76 return 0; 68 vfree(buf);
69 return count;
77} 70}
78 71
79static ssize_t snd_opl4_mem_proc_write(struct snd_info_entry *entry, 72static ssize_t snd_opl4_mem_proc_write(struct snd_info_entry *entry,
@@ -83,25 +76,18 @@ static ssize_t snd_opl4_mem_proc_write(struct snd_info_entry *entry,
83 size_t count, size_t pos) 76 size_t count, size_t pos)
84{ 77{
85 struct snd_opl4 *opl4 = entry->private_data; 78 struct snd_opl4 *opl4 = entry->private_data;
86 long size;
87 char *buf; 79 char *buf;
88 80
89 size = count; 81 buf = vmalloc(count);
90 if (pos + size > entry->size) 82 if (!buf)
91 size = entry->size - pos; 83 return -ENOMEM;
92 if (size > 0) { 84 if (copy_from_user(buf, _buf, count)) {
93 buf = vmalloc(size);
94 if (!buf)
95 return -ENOMEM;
96 if (copy_from_user(buf, _buf, size)) {
97 vfree(buf);
98 return -EFAULT;
99 }
100 snd_opl4_write_memory(opl4, buf, pos, size);
101 vfree(buf); 85 vfree(buf);
102 return size; 86 return -EFAULT;
103 } 87 }
104 return 0; 88 snd_opl4_write_memory(opl4, buf, pos, count);
89 vfree(buf);
90 return count;
105} 91}
106 92
107static loff_t snd_opl4_mem_proc_llseek(struct snd_info_entry *entry, 93static loff_t snd_opl4_mem_proc_llseek(struct snd_info_entry *entry,
diff --git a/sound/isa/gus/gus_mem_proc.c b/sound/isa/gus/gus_mem_proc.c
index b2d2dba6c860..faa2bec8f6b6 100644
--- a/sound/isa/gus/gus_mem_proc.c
+++ b/sound/isa/gus/gus_mem_proc.c
@@ -36,20 +36,14 @@ static ssize_t snd_gf1_mem_proc_dump(struct snd_info_entry *entry,
36 struct file *file, char __user *buf, 36 struct file *file, char __user *buf,
37 size_t count, loff_t pos) 37 size_t count, loff_t pos)
38{ 38{
39 long size;
40 struct gus_proc_private *priv = entry->private_data; 39 struct gus_proc_private *priv = entry->private_data;
41 struct snd_gus_card *gus = priv->gus; 40 struct snd_gus_card *gus = priv->gus;
42 int err; 41 int err;
43 42
44 size = count; 43 err = snd_gus_dram_read(gus, buf, pos, count, priv->rom);
45 if (pos + size > priv->size) 44 if (err < 0)
46 size = (long)priv->size - pos; 45 return err;
47 if (size > 0) { 46 return count;
48 if ((err = snd_gus_dram_read(gus, buf, pos, size, priv->rom)) < 0)
49 return err;
50 return size;
51 }
52 return 0;
53} 47}
54 48
55static loff_t snd_gf1_mem_proc_llseek(struct snd_info_entry *entry, 49static loff_t snd_gf1_mem_proc_llseek(struct snd_info_entry *entry,
diff --git a/sound/pci/cs4281.c b/sound/pci/cs4281.c
index b0bba2e86b12..6772070ed492 100644
--- a/sound/pci/cs4281.c
+++ b/sound/pci/cs4281.c
@@ -1144,17 +1144,11 @@ static ssize_t snd_cs4281_BA0_read(struct snd_info_entry *entry,
1144 struct file *file, char __user *buf, 1144 struct file *file, char __user *buf,
1145 size_t count, loff_t pos) 1145 size_t count, loff_t pos)
1146{ 1146{
1147 long size;
1148 struct cs4281 *chip = entry->private_data; 1147 struct cs4281 *chip = entry->private_data;
1149 1148
1150 size = count; 1149 if (copy_to_user_fromio(buf, chip->ba0 + pos, count))
1151 if (pos + size > CS4281_BA0_SIZE) 1150 return -EFAULT;
1152 size = (long)CS4281_BA0_SIZE - pos; 1151 return count;
1153 if (size > 0) {
1154 if (copy_to_user_fromio(buf, chip->ba0 + pos, size))
1155 return -EFAULT;
1156 }
1157 return size;
1158} 1152}
1159 1153
1160static ssize_t snd_cs4281_BA1_read(struct snd_info_entry *entry, 1154static ssize_t snd_cs4281_BA1_read(struct snd_info_entry *entry,
@@ -1162,17 +1156,11 @@ static ssize_t snd_cs4281_BA1_read(struct snd_info_entry *entry,
1162 struct file *file, char __user *buf, 1156 struct file *file, char __user *buf,
1163 size_t count, loff_t pos) 1157 size_t count, loff_t pos)
1164{ 1158{
1165 long size;
1166 struct cs4281 *chip = entry->private_data; 1159 struct cs4281 *chip = entry->private_data;
1167 1160
1168 size = count; 1161 if (copy_to_user_fromio(buf, chip->ba1 + pos, count))
1169 if (pos + size > CS4281_BA1_SIZE) 1162 return -EFAULT;
1170 size = (long)CS4281_BA1_SIZE - pos; 1163 return count;
1171 if (size > 0) {
1172 if (copy_to_user_fromio(buf, chip->ba1 + pos, size))
1173 return -EFAULT;
1174 }
1175 return size;
1176} 1164}
1177 1165
1178static struct snd_info_entry_ops snd_cs4281_proc_ops_BA0 = { 1166static struct snd_info_entry_ops snd_cs4281_proc_ops_BA0 = {
diff --git a/sound/pci/cs46xx/cs46xx_lib.c b/sound/pci/cs46xx/cs46xx_lib.c
index 08117b142381..aad37082cb6e 100644
--- a/sound/pci/cs46xx/cs46xx_lib.c
+++ b/sound/pci/cs46xx/cs46xx_lib.c
@@ -2662,17 +2662,11 @@ static ssize_t snd_cs46xx_io_read(struct snd_info_entry *entry,
2662 struct file *file, char __user *buf, 2662 struct file *file, char __user *buf,
2663 size_t count, loff_t pos) 2663 size_t count, loff_t pos)
2664{ 2664{
2665 long size;
2666 struct snd_cs46xx_region *region = entry->private_data; 2665 struct snd_cs46xx_region *region = entry->private_data;
2667 2666
2668 size = count; 2667 if (copy_to_user_fromio(buf, region->remap_addr + pos, count))
2669 if (pos + (size_t)size > region->size) 2668 return -EFAULT;
2670 size = region->size - pos; 2669 return count;
2671 if (size > 0) {
2672 if (copy_to_user_fromio(buf, region->remap_addr + pos, size))
2673 return -EFAULT;
2674 }
2675 return size;
2676} 2670}
2677 2671
2678static struct snd_info_entry_ops snd_cs46xx_proc_io_ops = { 2672static struct snd_info_entry_ops snd_cs46xx_proc_io_ops = {
diff --git a/sound/pci/emu10k1/emuproc.c b/sound/pci/emu10k1/emuproc.c
index 347b2415db59..bc38dd4d071f 100644
--- a/sound/pci/emu10k1/emuproc.c
+++ b/sound/pci/emu10k1/emuproc.c
@@ -346,10 +346,12 @@ static ssize_t snd_emu10k1_fx8010_read(struct snd_info_entry *entry,
346 struct file *file, char __user *buf, 346 struct file *file, char __user *buf,
347 size_t count, loff_t pos) 347 size_t count, loff_t pos)
348{ 348{
349 long size;
350 struct snd_emu10k1 *emu = entry->private_data; 349 struct snd_emu10k1 *emu = entry->private_data;
351 unsigned int offset; 350 unsigned int offset;
352 int tram_addr = 0; 351 int tram_addr = 0;
352 unsigned int *tmp;
353 long res;
354 unsigned int idx;
353 355
354 if (!strcmp(entry->name, "fx8010_tram_addr")) { 356 if (!strcmp(entry->name, "fx8010_tram_addr")) {
355 offset = TANKMEMADDRREGBASE; 357 offset = TANKMEMADDRREGBASE;
@@ -361,30 +363,25 @@ static ssize_t snd_emu10k1_fx8010_read(struct snd_info_entry *entry,
361 } else { 363 } else {
362 offset = emu->audigy ? A_FXGPREGBASE : FXGPREGBASE; 364 offset = emu->audigy ? A_FXGPREGBASE : FXGPREGBASE;
363 } 365 }
364 size = count; 366
365 if (pos + size > entry->size) 367 tmp = kmalloc(count + 8, GFP_KERNEL);
366 size = (long)entry->size - pos; 368 if (!tmp)
367 if (size > 0) { 369 return -ENOMEM;
368 unsigned int *tmp; 370 for (idx = 0; idx < ((pos & 3) + count + 3) >> 2; idx++) {
369 long res; 371 unsigned int val;
370 unsigned int idx; 372 val = snd_emu10k1_ptr_read(emu, offset + idx + (pos >> 2), 0);
371 if ((tmp = kmalloc(size + 8, GFP_KERNEL)) == NULL) 373 if (tram_addr && emu->audigy) {
372 return -ENOMEM; 374 val >>= 11;
373 for (idx = 0; idx < ((pos & 3) + size + 3) >> 2; idx++) 375 val |= snd_emu10k1_ptr_read(emu, 0x100 + idx + (pos >> 2), 0) << 20;
374 if (tram_addr && emu->audigy) {
375 tmp[idx] = snd_emu10k1_ptr_read(emu, offset + idx + (pos >> 2), 0) >> 11;
376 tmp[idx] |= snd_emu10k1_ptr_read(emu, 0x100 + idx + (pos >> 2), 0) << 20;
377 } else
378 tmp[idx] = snd_emu10k1_ptr_read(emu, offset + idx + (pos >> 2), 0);
379 if (copy_to_user(buf, ((char *)tmp) + (pos & 3), size))
380 res = -EFAULT;
381 else {
382 res = size;
383 } 376 }
384 kfree(tmp); 377 tmp[idx] = val;
385 return res;
386 } 378 }
387 return 0; 379 if (copy_to_user(buf, ((char *)tmp) + (pos & 3), count))
380 res = -EFAULT;
381 else
382 res = count;
383 kfree(tmp);
384 return res;
388} 385}
389 386
390static void snd_emu10k1_proc_voices_read(struct snd_info_entry *entry, 387static void snd_emu10k1_proc_voices_read(struct snd_info_entry *entry,
diff --git a/sound/pci/mixart/mixart.c b/sound/pci/mixart/mixart.c
index b5df78bcc25b..be95e005c81d 100644
--- a/sound/pci/mixart/mixart.c
+++ b/sound/pci/mixart/mixart.c
@@ -1161,13 +1161,7 @@ static ssize_t snd_mixart_BA0_read(struct snd_info_entry *entry,
1161 size_t count, loff_t pos) 1161 size_t count, loff_t pos)
1162{ 1162{
1163 struct mixart_mgr *mgr = entry->private_data; 1163 struct mixart_mgr *mgr = entry->private_data;
1164 unsigned long maxsize;
1165 1164
1166 if (pos >= MIXART_BA0_SIZE)
1167 return 0;
1168 maxsize = MIXART_BA0_SIZE - pos;
1169 if (count > maxsize)
1170 count = maxsize;
1171 count = count & ~3; /* make sure the read size is a multiple of 4 bytes */ 1165 count = count & ~3; /* make sure the read size is a multiple of 4 bytes */
1172 if (copy_to_user_fromio(buf, MIXART_MEM(mgr, pos), count)) 1166 if (copy_to_user_fromio(buf, MIXART_MEM(mgr, pos), count))
1173 return -EFAULT; 1167 return -EFAULT;
@@ -1183,13 +1177,7 @@ static ssize_t snd_mixart_BA1_read(struct snd_info_entry *entry,
1183 size_t count, loff_t pos) 1177 size_t count, loff_t pos)
1184{ 1178{
1185 struct mixart_mgr *mgr = entry->private_data; 1179 struct mixart_mgr *mgr = entry->private_data;
1186 unsigned long maxsize;
1187 1180
1188 if (pos > MIXART_BA1_SIZE)
1189 return 0;
1190 maxsize = MIXART_BA1_SIZE - pos;
1191 if (count > maxsize)
1192 count = maxsize;
1193 count = count & ~3; /* make sure the read size is a multiple of 4 bytes */ 1181 count = count & ~3; /* make sure the read size is a multiple of 4 bytes */
1194 if (copy_to_user_fromio(buf, MIXART_REG(mgr, pos), count)) 1182 if (copy_to_user_fromio(buf, MIXART_REG(mgr, pos), count))
1195 return -EFAULT; 1183 return -EFAULT;