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>
This commit is contained in:
@@ -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
|
|||||||
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
} 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,
|
|||||||
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,
|
|||||||
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;
|
||||||
|
Reference in New Issue
Block a user