diff options
author | Takashi Iwai <tiwai@suse.de> | 2010-02-17 14:24:46 +0100 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2010-02-17 14:24:46 +0100 |
commit | 7fb3a069bc5d3577409c2ae89f89cd264ff85816 (patch) | |
tree | 7fe3ba3b95faeecb01e4feafb9288ef4b523c6b3 /drivers/char/mem.c | |
parent | 291186e049d7f8178ad31d43c38a53889f25d79e (diff) | |
parent | 9d3415a8cc76ff65c6602a121ac318432c5cd7ba (diff) | |
download | linux-7fb3a069bc5d3577409c2ae89f89cd264ff85816.tar.bz2 |
Merge branch 'fix/misc' into topic/misc
Conflicts:
sound/pci/hda/patch_realtek.c
Diffstat (limited to 'drivers/char/mem.c')
-rw-r--r-- | drivers/char/mem.c | 30 |
1 files changed, 19 insertions, 11 deletions
diff --git a/drivers/char/mem.c b/drivers/char/mem.c index be832b6f8279..48788db4e280 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -395,6 +395,7 @@ static ssize_t read_kmem(struct file *file, char __user *buf, unsigned long p = *ppos; ssize_t low_count, read, sz; char * kbuf; /* k-addr because vread() takes vmlist_lock rwlock */ + int err = 0; read = 0; if (p < (unsigned long) high_memory) { @@ -441,12 +442,16 @@ static ssize_t read_kmem(struct file *file, char __user *buf, return -ENOMEM; while (count > 0) { sz = size_inside_page(p, count); + if (!is_vmalloc_or_module_addr((void *)p)) { + err = -ENXIO; + break; + } sz = vread(kbuf, (char *)p, sz); if (!sz) break; if (copy_to_user(buf, kbuf, sz)) { - free_page((unsigned long)kbuf); - return -EFAULT; + err = -EFAULT; + break; } count -= sz; buf += sz; @@ -455,8 +460,8 @@ static ssize_t read_kmem(struct file *file, char __user *buf, } free_page((unsigned long)kbuf); } - *ppos = p; - return read; + *ppos = p; + return read ? read : err; } @@ -520,6 +525,7 @@ static ssize_t write_kmem(struct file * file, const char __user * buf, ssize_t wrote = 0; ssize_t virtr = 0; char * kbuf; /* k-addr because vwrite() takes vmlist_lock rwlock */ + int err = 0; if (p < (unsigned long) high_memory) { unsigned long to_write = min_t(unsigned long, count, @@ -540,14 +546,16 @@ static ssize_t write_kmem(struct file * file, const char __user * buf, unsigned long sz = size_inside_page(p, count); unsigned long n; + if (!is_vmalloc_or_module_addr((void *)p)) { + err = -ENXIO; + break; + } n = copy_from_user(kbuf, buf, sz); if (n) { - if (wrote + virtr) - break; - free_page((unsigned long)kbuf); - return -EFAULT; + err = -EFAULT; + break; } - sz = vwrite(kbuf, (char *)p, sz); + vwrite(kbuf, (char *)p, sz); count -= sz; buf += sz; virtr += sz; @@ -556,8 +564,8 @@ static ssize_t write_kmem(struct file * file, const char __user * buf, free_page((unsigned long)kbuf); } - *ppos = p; - return virtr + wrote; + *ppos = p; + return virtr + wrote ? : err; } #endif |