Commit d97e1b78 authored by Takashi Iwai's avatar Takashi Iwai

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: default avatarTakashi Iwai <tiwai@suse.de>
parent 24e4a121
...@@ -232,10 +232,15 @@ static ssize_t snd_info_entry_read(struct file *file, char __user *buffer, ...@@ -232,10 +232,15 @@ static ssize_t snd_info_entry_read(struct file *file, char __user *buffer,
return -EFAULT; return -EFAULT;
break; break;
case SNDRV_INFO_CONTENT_DATA: case SNDRV_INFO_CONTENT_DATA:
if (entry->c.ops->read) if (pos >= entry->size)
return 0;
if (entry->c.ops->read) {
size = entry->size - pos;
size = min(count, size);
size = entry->c.ops->read(entry, size = entry->c.ops->read(entry,
data->file_private_data, data->file_private_data,
file, buffer, count, pos); file, buffer, size, pos);
}
break; break;
} }
if ((ssize_t) size > 0) if ((ssize_t) size > 0)
...@@ -282,10 +287,13 @@ static ssize_t snd_info_entry_write(struct file *file, const char __user *buffer ...@@ -282,10 +287,13 @@ static ssize_t snd_info_entry_write(struct file *file, const char __user *buffer
size = count; size = count;
break; break;
case SNDRV_INFO_CONTENT_DATA: case SNDRV_INFO_CONTENT_DATA:
if (entry->c.ops->write) if (entry->c.ops->write && count > 0) {
size_t maxsize = entry->size - pos;
count = min(count, maxsize);
size = entry->c.ops->write(entry, size = entry->c.ops->write(entry,
data->file_private_data, data->file_private_data,
file, buffer, count, pos); file, buffer, count, pos);
}
break; break;
} }
if ((ssize_t) size > 0) if ((ssize_t) size > 0)
......
...@@ -55,25 +55,18 @@ static ssize_t snd_opl4_mem_proc_read(struct snd_info_entry *entry, ...@@ -55,25 +55,18 @@ static ssize_t snd_opl4_mem_proc_read(struct snd_info_entry *entry,
size_t count, loff_t pos) size_t count, loff_t pos)
{ {
struct snd_opl4 *opl4 = entry->private_data; struct snd_opl4 *opl4 = entry->private_data;
long size;
char* buf; char* buf;
size = count; buf = vmalloc(count);
if (pos + size > entry->size) if (!buf)
size = entry->size - pos; return -ENOMEM;
if (size > 0) { snd_opl4_read_memory(opl4, buf, pos, count);
buf = vmalloc(size); if (copy_to_user(_buf, buf, count)) {
if (!buf)
return -ENOMEM;
snd_opl4_read_memory(opl4, buf, pos, size);
if (copy_to_user(_buf, buf, size)) {
vfree(buf);
return -EFAULT;
}
vfree(buf); vfree(buf);
return size; return -EFAULT;
} }
return 0; vfree(buf);
return count;
} }
static ssize_t snd_opl4_mem_proc_write(struct snd_info_entry *entry, 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,25 +76,18 @@ static ssize_t snd_opl4_mem_proc_write(struct snd_info_entry *entry,
size_t count, size_t pos) size_t count, size_t pos)
{ {
struct snd_opl4 *opl4 = entry->private_data; struct snd_opl4 *opl4 = entry->private_data;
long size;
char *buf; char *buf;
size = count; buf = vmalloc(count);
if (pos + size > entry->size) if (!buf)
size = entry->size - pos; return -ENOMEM;
if (size > 0) { if (copy_from_user(buf, _buf, count)) {
buf = vmalloc(size);
if (!buf)
return -ENOMEM;
if (copy_from_user(buf, _buf, size)) {
vfree(buf);
return -EFAULT;
}
snd_opl4_write_memory(opl4, buf, pos, size);
vfree(buf); vfree(buf);
return size; return -EFAULT;
} }
return 0; snd_opl4_write_memory(opl4, buf, pos, count);
vfree(buf);
return count;
} }
static loff_t snd_opl4_mem_proc_llseek(struct snd_info_entry *entry, static loff_t snd_opl4_mem_proc_llseek(struct snd_info_entry *entry,
......
...@@ -36,20 +36,14 @@ static ssize_t snd_gf1_mem_proc_dump(struct snd_info_entry *entry, ...@@ -36,20 +36,14 @@ static ssize_t snd_gf1_mem_proc_dump(struct snd_info_entry *entry,
struct file *file, char __user *buf, struct file *file, char __user *buf,
size_t count, loff_t pos) size_t count, loff_t pos)
{ {
long size;
struct gus_proc_private *priv = entry->private_data; struct gus_proc_private *priv = entry->private_data;
struct snd_gus_card *gus = priv->gus; struct snd_gus_card *gus = priv->gus;
int err; int err;
size = count; err = snd_gus_dram_read(gus, buf, pos, count, priv->rom);
if (pos + size > priv->size) if (err < 0)
size = (long)priv->size - pos; return err;
if (size > 0) { return count;
if ((err = snd_gus_dram_read(gus, buf, pos, size, priv->rom)) < 0)
return err;
return size;
}
return 0;
} }
static loff_t snd_gf1_mem_proc_llseek(struct snd_info_entry *entry, static loff_t snd_gf1_mem_proc_llseek(struct snd_info_entry *entry,
......
...@@ -1144,17 +1144,11 @@ static ssize_t snd_cs4281_BA0_read(struct snd_info_entry *entry, ...@@ -1144,17 +1144,11 @@ static ssize_t snd_cs4281_BA0_read(struct snd_info_entry *entry,
struct file *file, char __user *buf, struct file *file, char __user *buf,
size_t count, loff_t pos) size_t count, loff_t pos)
{ {
long size;
struct cs4281 *chip = entry->private_data; struct cs4281 *chip = entry->private_data;
size = count; if (copy_to_user_fromio(buf, chip->ba0 + pos, count))
if (pos + size > CS4281_BA0_SIZE) return -EFAULT;
size = (long)CS4281_BA0_SIZE - pos; return count;
if (size > 0) {
if (copy_to_user_fromio(buf, chip->ba0 + pos, size))
return -EFAULT;
}
return size;
} }
static ssize_t snd_cs4281_BA1_read(struct snd_info_entry *entry, 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,17 +1156,11 @@ static ssize_t snd_cs4281_BA1_read(struct snd_info_entry *entry,
struct file *file, char __user *buf, struct file *file, char __user *buf,
size_t count, loff_t pos) size_t count, loff_t pos)
{ {
long size;
struct cs4281 *chip = entry->private_data; struct cs4281 *chip = entry->private_data;
size = count; if (copy_to_user_fromio(buf, chip->ba1 + pos, count))
if (pos + size > CS4281_BA1_SIZE) return -EFAULT;
size = (long)CS4281_BA1_SIZE - pos; return count;
if (size > 0) {
if (copy_to_user_fromio(buf, chip->ba1 + pos, size))
return -EFAULT;
}
return size;
} }
static struct snd_info_entry_ops snd_cs4281_proc_ops_BA0 = { static struct snd_info_entry_ops snd_cs4281_proc_ops_BA0 = {
......
...@@ -2662,17 +2662,11 @@ static ssize_t snd_cs46xx_io_read(struct snd_info_entry *entry, ...@@ -2662,17 +2662,11 @@ static ssize_t snd_cs46xx_io_read(struct snd_info_entry *entry,
struct file *file, char __user *buf, struct file *file, char __user *buf,
size_t count, loff_t pos) size_t count, loff_t pos)
{ {
long size;
struct snd_cs46xx_region *region = entry->private_data; struct snd_cs46xx_region *region = entry->private_data;
size = count; if (copy_to_user_fromio(buf, region->remap_addr + pos, count))
if (pos + (size_t)size > region->size) return -EFAULT;
size = region->size - pos; return count;
if (size > 0) {
if (copy_to_user_fromio(buf, region->remap_addr + pos, size))
return -EFAULT;
}
return size;
} }
static struct snd_info_entry_ops snd_cs46xx_proc_io_ops = { static struct snd_info_entry_ops snd_cs46xx_proc_io_ops = {
......
...@@ -346,10 +346,12 @@ static ssize_t snd_emu10k1_fx8010_read(struct snd_info_entry *entry, ...@@ -346,10 +346,12 @@ static ssize_t snd_emu10k1_fx8010_read(struct snd_info_entry *entry,
struct file *file, char __user *buf, struct file *file, char __user *buf,
size_t count, loff_t pos) size_t count, loff_t pos)
{ {
long size;
struct snd_emu10k1 *emu = entry->private_data; struct snd_emu10k1 *emu = entry->private_data;
unsigned int offset; unsigned int offset;
int tram_addr = 0; int tram_addr = 0;
unsigned int *tmp;
long res;
unsigned int idx;
if (!strcmp(entry->name, "fx8010_tram_addr")) { if (!strcmp(entry->name, "fx8010_tram_addr")) {
offset = TANKMEMADDRREGBASE; offset = TANKMEMADDRREGBASE;
...@@ -361,30 +363,25 @@ static ssize_t snd_emu10k1_fx8010_read(struct snd_info_entry *entry, ...@@ -361,30 +363,25 @@ static ssize_t snd_emu10k1_fx8010_read(struct snd_info_entry *entry,
} else { } else {
offset = emu->audigy ? A_FXGPREGBASE : FXGPREGBASE; offset = emu->audigy ? A_FXGPREGBASE : FXGPREGBASE;
} }
size = count;
if (pos + size > entry->size) tmp = kmalloc(count + 8, GFP_KERNEL);
size = (long)entry->size - pos; if (!tmp)
if (size > 0) { return -ENOMEM;
unsigned int *tmp; for (idx = 0; idx < ((pos & 3) + count + 3) >> 2; idx++) {
long res; unsigned int val;
unsigned int idx; val = snd_emu10k1_ptr_read(emu, offset + idx + (pos >> 2), 0);
if ((tmp = kmalloc(size + 8, GFP_KERNEL)) == NULL) if (tram_addr && emu->audigy) {
return -ENOMEM; val >>= 11;
for (idx = 0; idx < ((pos & 3) + size + 3) >> 2; idx++) val |= snd_emu10k1_ptr_read(emu, 0x100 + idx + (pos >> 2), 0) << 20;
if (tram_addr && emu->audigy) {
tmp[idx] = snd_emu10k1_ptr_read(emu, offset + idx + (pos >> 2), 0) >> 11;
tmp[idx] |= snd_emu10k1_ptr_read(emu, 0x100 + idx + (pos >> 2), 0) << 20;
} else
tmp[idx] = snd_emu10k1_ptr_read(emu, offset + idx + (pos >> 2), 0);
if (copy_to_user(buf, ((char *)tmp) + (pos & 3), size))
res = -EFAULT;
else {
res = size;
} }
kfree(tmp); tmp[idx] = val;
return res;
} }
return 0; if (copy_to_user(buf, ((char *)tmp) + (pos & 3), count))
res = -EFAULT;
else
res = count;
kfree(tmp);
return res;
} }
static void snd_emu10k1_proc_voices_read(struct snd_info_entry *entry, static void snd_emu10k1_proc_voices_read(struct snd_info_entry *entry,
......
...@@ -1161,13 +1161,7 @@ static ssize_t snd_mixart_BA0_read(struct snd_info_entry *entry, ...@@ -1161,13 +1161,7 @@ static ssize_t snd_mixart_BA0_read(struct snd_info_entry *entry,
size_t count, loff_t pos) size_t count, loff_t pos)
{ {
struct mixart_mgr *mgr = entry->private_data; struct mixart_mgr *mgr = entry->private_data;
unsigned long maxsize;
if (pos >= MIXART_BA0_SIZE)
return 0;
maxsize = MIXART_BA0_SIZE - pos;
if (count > maxsize)
count = maxsize;
count = count & ~3; /* make sure the read size is a multiple of 4 bytes */ count = count & ~3; /* make sure the read size is a multiple of 4 bytes */
if (copy_to_user_fromio(buf, MIXART_MEM(mgr, pos), count)) if (copy_to_user_fromio(buf, MIXART_MEM(mgr, pos), count))
return -EFAULT; return -EFAULT;
...@@ -1183,13 +1177,7 @@ static ssize_t snd_mixart_BA1_read(struct snd_info_entry *entry, ...@@ -1183,13 +1177,7 @@ static ssize_t snd_mixart_BA1_read(struct snd_info_entry *entry,
size_t count, loff_t pos) size_t count, loff_t pos)
{ {
struct mixart_mgr *mgr = entry->private_data; struct mixart_mgr *mgr = entry->private_data;
unsigned long maxsize;
if (pos > MIXART_BA1_SIZE)
return 0;
maxsize = MIXART_BA1_SIZE - pos;
if (count > maxsize)
count = maxsize;
count = count & ~3; /* make sure the read size is a multiple of 4 bytes */ count = count & ~3; /* make sure the read size is a multiple of 4 bytes */
if (copy_to_user_fromio(buf, MIXART_REG(mgr, pos), count)) if (copy_to_user_fromio(buf, MIXART_REG(mgr, pos), count))
return -EFAULT; return -EFAULT;
......
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