Commit 6b344d83 authored by KAMEZAWA Hiroyuki's avatar KAMEZAWA Hiroyuki Committed by Greg Kroah-Hartman

devmem: check vmalloc address on kmem read/write

commit 325fda71

[ cebbert@redhat.com : backport to 2.6.32 ]

devmem: check vmalloc address on kmem read/write

Otherwise vmalloc_to_page() will BUG().

This also makes the kmem read/write implementation aligned with mem(4):
"References to nonexistent locations cause errors to be returned." Here we
return -ENXIO (inspired by Hugh) if no bytes have been transfered to/from
user space, otherwise return partial read/write results.
Signed-off-by: default avatarKAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
Signed-off-by: default avatarWu Fengguang <fengguang.wu@intel.com>
Cc: Greg Kroah-Hartman <gregkh@suse.de>
Cc: Hugh Dickins <hugh.dickins@tiscali.co.uk>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
Cc: Chuck Ebbert <cebbert@redhat.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 0e1104ad
......@@ -421,6 +421,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) {
......@@ -469,12 +470,16 @@ static ssize_t read_kmem(struct file *file, char __user *buf,
while (count > 0) {
int len = size_inside_page(p, count);
if (!is_vmalloc_or_module_addr((void *)p)) {
err = -ENXIO;
break;
}
len = vread(kbuf, (char *)p, len);
if (!len)
break;
if (copy_to_user(buf, kbuf, len)) {
free_page((unsigned long)kbuf);
return -EFAULT;
err = -EFAULT;
break;
}
count -= len;
buf += len;
......@@ -484,7 +489,7 @@ static ssize_t read_kmem(struct file *file, char __user *buf,
free_page((unsigned long)kbuf);
}
*ppos = p;
return read;
return read ? read : err;
}
......@@ -553,6 +558,7 @@ static ssize_t write_kmem(struct file * file, const char __user * buf,
ssize_t virtr = 0;
ssize_t written;
char * kbuf; /* k-addr because vwrite() takes vmlist_lock rwlock */
int err = 0;
if (p < (unsigned long) high_memory) {
......@@ -576,13 +582,15 @@ static ssize_t write_kmem(struct file * file, const char __user * buf,
while (count > 0) {
int len = size_inside_page(p, count);
if (!is_vmalloc_or_module_addr((void *)p)) {
err = -ENXIO;
break;
}
if (len) {
written = copy_from_user(kbuf, buf, len);
if (written) {
if (wrote + virtr)
err = -EFAULT;
break;
free_page((unsigned long)kbuf);
return -EFAULT;
}
}
len = vwrite(kbuf, (char *)p, len);
......@@ -595,7 +603,7 @@ static ssize_t write_kmem(struct file * file, const char __user * buf,
}
*ppos = p;
return virtr + wrote;
return virtr + wrote ? : err;
}
#endif
......
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