diff options
author | Takashi Iwai <tiwai@suse.de> | 2010-04-13 05:33:54 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2010-04-13 06:01:14 -0400 |
commit | d97e1b78239c7e7e441088e0b644bd3b076002e6 (patch) | |
tree | b05b5085bea932662ce60061d5b4b93834683327 | |
parent | 24e4a1211f691fc671de44685430dbad757d8487 (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.c | 14 | ||||
-rw-r--r-- | sound/drivers/opl4/opl4_proc.c | 46 | ||||
-rw-r--r-- | sound/isa/gus/gus_mem_proc.c | 14 | ||||
-rw-r--r-- | sound/pci/cs4281.c | 24 | ||||
-rw-r--r-- | sound/pci/cs46xx/cs46xx_lib.c | 12 | ||||
-rw-r--r-- | sound/pci/emu10k1/emuproc.c | 43 | ||||
-rw-r--r-- | sound/pci/mixart/mixart.c | 12 |
7 files changed, 60 insertions, 105 deletions
diff --git a/sound/core/info.c b/sound/core/info.c index ff968be8167..f90a6fd43fb 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 eb72814dfd5..210b89de06d 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 | ||
79 | static ssize_t snd_opl4_mem_proc_write(struct snd_info_entry *entry, | 72 | static 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 | ||
107 | static loff_t snd_opl4_mem_proc_llseek(struct snd_info_entry *entry, | 93 | static 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 b2d2dba6c86..faa2bec8f6b 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 | ||
55 | static loff_t snd_gf1_mem_proc_llseek(struct snd_info_entry *entry, | 49 | static 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 b0bba2e86b1..6772070ed49 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 | ||
1160 | static ssize_t snd_cs4281_BA1_read(struct snd_info_entry *entry, | 1154 | static 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 | ||
1178 | static struct snd_info_entry_ops snd_cs4281_proc_ops_BA0 = { | 1166 | static 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 08117b14238..aad37082cb6 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 | ||
2678 | static struct snd_info_entry_ops snd_cs46xx_proc_io_ops = { | 2672 | static 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 347b2415db5..bc38dd4d071 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 | ||
390 | static void snd_emu10k1_proc_voices_read(struct snd_info_entry *entry, | 387 | static 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 b5df78bcc25..be95e005c81 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; |