Skip to content

Commit

Permalink
ALSA: info - Check file position validity in common layer
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
tiwai committed Apr 13, 2010
1 parent 24e4a12 commit d97e1b7
Show file tree
Hide file tree
Showing 7 changed files with 60 additions and 105 deletions.
14 changes: 11 additions & 3 deletions sound/core/info.c
Original file line number Diff line number Diff line change
Expand Up @@ -232,10 +232,15 @@ static ssize_t snd_info_entry_read(struct file *file, char __user *buffer,
return -EFAULT;
break;
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,
data->file_private_data,
file, buffer, count, pos);
file, buffer, size, pos);
}
break;
}
if ((ssize_t) size > 0)
Expand Down Expand Up @@ -282,10 +287,13 @@ static ssize_t snd_info_entry_write(struct file *file, const char __user *buffer
size = count;
break;
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,
data->file_private_data,
file, buffer, count, pos);
}
break;
}
if ((ssize_t) size > 0)
Expand Down
46 changes: 16 additions & 30 deletions sound/drivers/opl4/opl4_proc.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,25 +55,18 @@ static ssize_t snd_opl4_mem_proc_read(struct snd_info_entry *entry,
size_t count, loff_t pos)
{
struct snd_opl4 *opl4 = entry->private_data;
long size;
char* buf;

size = count;
if (pos + size > entry->size)
size = entry->size - pos;
if (size > 0) {
buf = vmalloc(size);
if (!buf)
return -ENOMEM;
snd_opl4_read_memory(opl4, buf, pos, size);
if (copy_to_user(_buf, buf, size)) {
vfree(buf);
return -EFAULT;
}
buf = vmalloc(count);
if (!buf)
return -ENOMEM;
snd_opl4_read_memory(opl4, buf, pos, count);
if (copy_to_user(_buf, buf, count)) {
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,
Expand All @@ -83,25 +76,18 @@ static ssize_t snd_opl4_mem_proc_write(struct snd_info_entry *entry,
size_t count, size_t pos)
{
struct snd_opl4 *opl4 = entry->private_data;
long size;
char *buf;

size = count;
if (pos + size > entry->size)
size = entry->size - pos;
if (size > 0) {
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);
buf = vmalloc(count);
if (!buf)
return -ENOMEM;
if (copy_from_user(buf, _buf, count)) {
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,
Expand Down
14 changes: 4 additions & 10 deletions sound/isa/gus/gus_mem_proc.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,20 +36,14 @@ static ssize_t snd_gf1_mem_proc_dump(struct snd_info_entry *entry,
struct file *file, char __user *buf,
size_t count, loff_t pos)
{
long size;
struct gus_proc_private *priv = entry->private_data;
struct snd_gus_card *gus = priv->gus;
int err;

size = count;
if (pos + size > priv->size)
size = (long)priv->size - pos;
if (size > 0) {
if ((err = snd_gus_dram_read(gus, buf, pos, size, priv->rom)) < 0)
return err;
return size;
}
return 0;
err = snd_gus_dram_read(gus, buf, pos, count, priv->rom);
if (err < 0)
return err;
return count;
}

static loff_t snd_gf1_mem_proc_llseek(struct snd_info_entry *entry,
Expand Down
24 changes: 6 additions & 18 deletions sound/pci/cs4281.c
Original file line number Diff line number Diff line change
Expand Up @@ -1144,35 +1144,23 @@ static ssize_t snd_cs4281_BA0_read(struct snd_info_entry *entry,
struct file *file, char __user *buf,
size_t count, loff_t pos)
{
long size;
struct cs4281 *chip = entry->private_data;

size = count;
if (pos + size > CS4281_BA0_SIZE)
size = (long)CS4281_BA0_SIZE - pos;
if (size > 0) {
if (copy_to_user_fromio(buf, chip->ba0 + pos, size))
return -EFAULT;
}
return size;
if (copy_to_user_fromio(buf, chip->ba0 + pos, count))
return -EFAULT;
return count;
}

static ssize_t snd_cs4281_BA1_read(struct snd_info_entry *entry,
void *file_private_data,
struct file *file, char __user *buf,
size_t count, loff_t pos)
{
long size;
struct cs4281 *chip = entry->private_data;

size = count;
if (pos + size > CS4281_BA1_SIZE)
size = (long)CS4281_BA1_SIZE - pos;
if (size > 0) {
if (copy_to_user_fromio(buf, chip->ba1 + pos, size))
return -EFAULT;
}
return size;
if (copy_to_user_fromio(buf, chip->ba1 + pos, count))
return -EFAULT;
return count;
}

static struct snd_info_entry_ops snd_cs4281_proc_ops_BA0 = {
Expand Down
12 changes: 3 additions & 9 deletions sound/pci/cs46xx/cs46xx_lib.c
Original file line number Diff line number Diff line change
Expand Up @@ -2662,17 +2662,11 @@ static ssize_t snd_cs46xx_io_read(struct snd_info_entry *entry,
struct file *file, char __user *buf,
size_t count, loff_t pos)
{
long size;
struct snd_cs46xx_region *region = entry->private_data;

size = count;
if (pos + (size_t)size > region->size)
size = region->size - pos;
if (size > 0) {
if (copy_to_user_fromio(buf, region->remap_addr + pos, size))
return -EFAULT;
}
return size;
if (copy_to_user_fromio(buf, region->remap_addr + pos, count))
return -EFAULT;
return count;
}

static struct snd_info_entry_ops snd_cs46xx_proc_io_ops = {
Expand Down
43 changes: 20 additions & 23 deletions sound/pci/emu10k1/emuproc.c
Original file line number Diff line number Diff line change
Expand Up @@ -346,10 +346,12 @@ static ssize_t snd_emu10k1_fx8010_read(struct snd_info_entry *entry,
struct file *file, char __user *buf,
size_t count, loff_t pos)
{
long size;
struct snd_emu10k1 *emu = entry->private_data;
unsigned int offset;
int tram_addr = 0;
unsigned int *tmp;
long res;
unsigned int idx;

if (!strcmp(entry->name, "fx8010_tram_addr")) {
offset = TANKMEMADDRREGBASE;
Expand All @@ -361,30 +363,25 @@ static ssize_t snd_emu10k1_fx8010_read(struct snd_info_entry *entry,
} else {
offset = emu->audigy ? A_FXGPREGBASE : FXGPREGBASE;
}
size = count;
if (pos + size > entry->size)
size = (long)entry->size - pos;
if (size > 0) {
unsigned int *tmp;
long res;
unsigned int idx;
if ((tmp = kmalloc(size + 8, GFP_KERNEL)) == NULL)
return -ENOMEM;
for (idx = 0; idx < ((pos & 3) + size + 3) >> 2; idx++)
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;

tmp = kmalloc(count + 8, GFP_KERNEL);
if (!tmp)
return -ENOMEM;
for (idx = 0; idx < ((pos & 3) + count + 3) >> 2; idx++) {
unsigned int val;
val = snd_emu10k1_ptr_read(emu, offset + idx + (pos >> 2), 0);
if (tram_addr && emu->audigy) {
val >>= 11;
val |= snd_emu10k1_ptr_read(emu, 0x100 + idx + (pos >> 2), 0) << 20;
}
kfree(tmp);
return res;
tmp[idx] = val;
}
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,
Expand Down
12 changes: 0 additions & 12 deletions sound/pci/mixart/mixart.c
Original file line number Diff line number Diff line change
Expand Up @@ -1161,13 +1161,7 @@ static ssize_t snd_mixart_BA0_read(struct snd_info_entry *entry,
size_t count, loff_t pos)
{
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 */
if (copy_to_user_fromio(buf, MIXART_MEM(mgr, pos), count))
return -EFAULT;
Expand All @@ -1183,13 +1177,7 @@ static ssize_t snd_mixart_BA1_read(struct snd_info_entry *entry,
size_t count, loff_t pos)
{
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 */
if (copy_to_user_fromio(buf, MIXART_REG(mgr, pos), count))
return -EFAULT;
Expand Down

0 comments on commit d97e1b7

Please sign in to comment.