* [PATCH 0/4] /proc/kmem fixes and hwpoison bits v3
@ 2009-09-16 3:00 Wu Fengguang
2009-09-16 3:00 ` [PATCH 1/4] devmem: fix kmem write bug on memory holes Wu Fengguang
` (3 more replies)
0 siblings, 4 replies; 5+ messages in thread
From: Wu Fengguang @ 2009-09-16 3:00 UTC (permalink / raw)
To: Andrew Morton, KAMEZAWA Hiroyuki
Cc: Benjamin Herrenschmidt, Christoph Lameter, Ingo Molnar, Tejun Heo,
Nick Piggin, Wu Fengguang, LKML, linux-mm
Hi,
Here are 2 bug fixes and also hwpoison checks for /dev/mem and /dev/kmem.
The bug fixes are intended for this merge window.
Changes since v2:
- remove the prototype change and make the bug fix simple
- add hwpoison checks for /dev/mem (this is in fact an old patch for me)
Changes since v1:
- change vread()/vwrite() prototype (proposed by Kame)
- include Kame's is_vmalloc_or_module_addr() check and use Hugh's -ENXIO.
- I decided not to use __GFP_ZERO, since the buf will be reused in the loop,
so it would be better for vread to zero-fill it each time.
- removed the hwpoison checks for vmalloc pages. It seems that vread/vwrite
could be simplified to handle one single page, and the hwpoison bits can be
considered after that.
Thanks,
Fengguang
--
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH 1/4] devmem: fix kmem write bug on memory holes
2009-09-16 3:00 [PATCH 0/4] /proc/kmem fixes and hwpoison bits v3 Wu Fengguang
@ 2009-09-16 3:00 ` Wu Fengguang
2009-09-16 3:00 ` [PATCH 2/4] devmem: check vmalloc address on kmem read/write Wu Fengguang
` (2 subsequent siblings)
3 siblings, 0 replies; 5+ messages in thread
From: Wu Fengguang @ 2009-09-16 3:00 UTC (permalink / raw)
To: Andrew Morton, KAMEZAWA Hiroyuki
Cc: Benjamin Herrenschmidt, Andi Kleen, Christoph Lameter,
Ingo Molnar, Tejun Heo, Nick Piggin, Wu Fengguang, LKML, linux-mm
[-- Attachment #1: vwrite-fix.patch --]
[-- Type: text/plain, Size: 1079 bytes --]
write_kmem() used to assume vwrite() always return the full buffer length.
However now vwrite() could return 0 to indicate memory hole. This creates
a bug that "buf" is not advanced accordingly.
Fix it to simply ignore the return value, hence the memory hole.
CC: Andi Kleen <andi@firstfloor.org>
CC: Benjamin Herrenschmidt <benh@kernel.crashing.org>
CC: Christoph Lameter <cl@linux-foundation.org>
CC: Ingo Molnar <mingo@elte.hu>
CC: Tejun Heo <tj@kernel.org>
CC: Nick Piggin <npiggin@suse.de>
CC: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
Signed-off-by: Wu Fengguang <fengguang.wu@intel.com>
---
drivers/char/mem.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- linux-mm.orig/drivers/char/mem.c 2009-09-16 10:41:10.000000000 +0800
+++ linux-mm/drivers/char/mem.c 2009-09-16 10:48:16.000000000 +0800
@@ -548,7 +548,7 @@ static ssize_t write_kmem(struct file *
free_page((unsigned long)kbuf);
return -EFAULT;
}
- sz = vwrite(kbuf, (char *)p, sz);
+ vwrite(kbuf, (char *)p, sz);
count -= sz;
buf += sz;
virtr += sz;
--
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH 2/4] devmem: check vmalloc address on kmem read/write
2009-09-16 3:00 [PATCH 0/4] /proc/kmem fixes and hwpoison bits v3 Wu Fengguang
2009-09-16 3:00 ` [PATCH 1/4] devmem: fix kmem write bug on memory holes Wu Fengguang
@ 2009-09-16 3:00 ` Wu Fengguang
2009-09-16 3:00 ` [PATCH 3/4] HWPOISON: prevent /dev/kmem users from accessing hwpoison pages Wu Fengguang
2009-09-16 3:00 ` [PATCH 4/4] HWPOISON: stop /dev/mem " Wu Fengguang
3 siblings, 0 replies; 5+ messages in thread
From: Wu Fengguang @ 2009-09-16 3:00 UTC (permalink / raw)
To: Andrew Morton, KAMEZAWA Hiroyuki
Cc: Benjamin Herrenschmidt, Greg Kroah-Hartman, Hugh Dickins,
Wu Fengguang, Christoph Lameter, Ingo Molnar, Tejun Heo,
Nick Piggin, LKML, linux-mm
[-- Attachment #1: vmalloc-addr-fix.patch --]
[-- Type: text/plain, Size: 2616 bytes --]
From: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
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.
CC: Greg Kroah-Hartman <gregkh@suse.de>
CC: Hugh Dickins <hugh.dickins@tiscali.co.uk>
Signed-off-by: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
Signed-off-by: Wu Fengguang <fengguang.wu@intel.com>
---
drivers/char/mem.c | 24 ++++++++++++++++--------
1 file changed, 16 insertions(+), 8 deletions(-)
--- linux-mm.orig/drivers/char/mem.c 2009-09-16 10:48:16.000000000 +0800
+++ linux-mm/drivers/char/mem.c 2009-09-16 10:57:13.000000000 +0800
@@ -396,6 +396,7 @@ static ssize_t read_kmem(struct file *fi
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) {
@@ -442,12 +443,16 @@ static ssize_t read_kmem(struct file *fi
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;
@@ -457,7 +462,7 @@ static ssize_t read_kmem(struct file *fi
free_page((unsigned long)kbuf);
}
*ppos = p;
- return read;
+ return read ? read : err;
}
@@ -521,6 +526,7 @@ static ssize_t write_kmem(struct file *
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,
@@ -541,12 +547,14 @@ static ssize_t write_kmem(struct file *
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;
}
vwrite(kbuf, (char *)p, sz);
count -= sz;
@@ -558,7 +566,7 @@ static ssize_t write_kmem(struct file *
}
*ppos = p;
- return virtr + wrote;
+ return virtr + wrote ? : err;
}
#endif
--
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH 3/4] HWPOISON: prevent /dev/kmem users from accessing hwpoison pages
2009-09-16 3:00 [PATCH 0/4] /proc/kmem fixes and hwpoison bits v3 Wu Fengguang
2009-09-16 3:00 ` [PATCH 1/4] devmem: fix kmem write bug on memory holes Wu Fengguang
2009-09-16 3:00 ` [PATCH 2/4] devmem: check vmalloc address on kmem read/write Wu Fengguang
@ 2009-09-16 3:00 ` Wu Fengguang
2009-09-16 3:00 ` [PATCH 4/4] HWPOISON: stop /dev/mem " Wu Fengguang
3 siblings, 0 replies; 5+ messages in thread
From: Wu Fengguang @ 2009-09-16 3:00 UTC (permalink / raw)
To: Andrew Morton, KAMEZAWA Hiroyuki
Cc: Benjamin Herrenschmidt, Greg KH, Andi Kleen, Christoph Lameter,
Ingo Molnar, Tejun Heo, Nick Piggin, Wu Fengguang, LKML, linux-mm
[-- Attachment #1: kmem-dev-kmem.patch --]
[-- Type: text/plain, Size: 1896 bytes --]
When /dev/kmem read()/write() encounters hwpoison page, stop it
and return the amount of work done till now.
Vmalloc pages are not checked for now, to avoid conflicts with
ongoing vread/vwrite works.
CC: Greg KH <greg@kroah.com>
CC: Andi Kleen <andi@firstfloor.org>
CC: Benjamin Herrenschmidt <benh@kernel.crashing.org>
CC: Christoph Lameter <cl@linux-foundation.org>
CC: Ingo Molnar <mingo@elte.hu>
CC: Tejun Heo <tj@kernel.org>
CC: Nick Piggin <npiggin@suse.de>
Reviewed-by: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
Signed-off-by: Wu Fengguang <fengguang.wu@intel.com>
---
drivers/char/mem.c | 18 ++++++++++++++----
1 file changed, 14 insertions(+), 4 deletions(-)
--- linux-mm.orig/drivers/char/mem.c 2009-09-16 09:25:34.000000000 +0800
+++ linux-mm/drivers/char/mem.c 2009-09-16 09:25:43.000000000 +0800
@@ -427,6 +427,9 @@ static ssize_t read_kmem(struct file *fi
*/
kbuf = xlate_dev_kmem_ptr((char *)p);
+ if (unlikely(virt_addr_valid(kbuf) &&
+ PageHWPoison(virt_to_page(kbuf))))
+ return -EIO;
if (copy_to_user(buf, kbuf, sz))
return -EFAULT;
buf += sz;
@@ -472,6 +475,7 @@ do_write_kmem(unsigned long p, const cha
{
ssize_t written, sz;
unsigned long copied;
+ int err = 0;
written = 0;
#ifdef __ARCH_HAS_NO_PAGE_ZERO_MAPPED
@@ -498,13 +502,19 @@ do_write_kmem(unsigned long p, const cha
*/
ptr = xlate_dev_kmem_ptr((char *)p);
+ if (unlikely(virt_addr_valid(ptr) &&
+ PageHWPoison(virt_to_page(ptr)))) {
+ err = -EIO;
+ break;
+ }
+
copied = copy_from_user(ptr, buf, sz);
if (copied) {
written += sz - copied;
- if (written)
- break;
- return -EFAULT;
+ err = -EFAULT;
+ break;
}
+
buf += sz;
p += sz;
count -= sz;
@@ -512,7 +522,7 @@ do_write_kmem(unsigned long p, const cha
}
*ppos += written;
- return written;
+ return written ? written : err;
}
--
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH 4/4] HWPOISON: stop /dev/mem users from accessing hwpoison pages
2009-09-16 3:00 [PATCH 0/4] /proc/kmem fixes and hwpoison bits v3 Wu Fengguang
` (2 preceding siblings ...)
2009-09-16 3:00 ` [PATCH 3/4] HWPOISON: prevent /dev/kmem users from accessing hwpoison pages Wu Fengguang
@ 2009-09-16 3:00 ` Wu Fengguang
3 siblings, 0 replies; 5+ messages in thread
From: Wu Fengguang @ 2009-09-16 3:00 UTC (permalink / raw)
To: Andrew Morton, KAMEZAWA Hiroyuki
Cc: Benjamin Herrenschmidt, Greg KH, Wu Fengguang, Christoph Lameter,
Ingo Molnar, Tejun Heo, Nick Piggin, LKML, linux-mm
[-- Attachment #1: kmem-dev-mem.patch --]
[-- Type: text/plain, Size: 3378 bytes --]
Return EIO when user space tries to read/write/mmap hwpoison pages
via the /dev/mem interface.
The approach: rename range_is_allowed() to devmem_check_pfn_range(), and
add PageHWPoison() test into it. So as to fail the whole request if it
contains any hwpoison page. Partial write into physical memory seems
don't make much sense, and user space can avoid this limit by doing
1-page read/writes.
CC: Greg KH <greg@kroah.com>
CC: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
Reviewed-by: Andi Kleen <andi@firstfloor.org>
Signed-off-by: Wu Fengguang <fengguang.wu@intel.com>
---
drivers/char/mem.c | 37 ++++++++++++++++++++-----------------
1 file changed, 20 insertions(+), 17 deletions(-)
--- linux-mm.orig/drivers/char/mem.c 2009-09-16 09:57:36.000000000 +0800
+++ linux-mm/drivers/char/mem.c 2009-09-16 09:59:37.000000000 +0800
@@ -90,31 +90,28 @@ static inline int valid_mmap_phys_addr_r
}
#endif
-#ifdef CONFIG_STRICT_DEVMEM
-static inline int range_is_allowed(unsigned long pfn, unsigned long size)
+static int devmem_check_pfn_range(unsigned long pfn, unsigned long size)
{
u64 from = ((u64)pfn) << PAGE_SHIFT;
u64 to = from + size;
u64 cursor = from;
while (cursor < to) {
+#ifdef CONFIG_STRICT_DEVMEM
if (!devmem_is_allowed(pfn)) {
printk(KERN_INFO
"Program %s tried to access /dev/mem between %Lx->%Lx.\n",
current->comm, from, to);
- return 0;
+ return -EPERM;
}
+#endif
+ if (pfn_valid(pfn) && PageHWPoison(pfn_to_page(pfn)))
+ return -EIO;
cursor += PAGE_SIZE;
pfn++;
}
- return 1;
-}
-#else
-static inline int range_is_allowed(unsigned long pfn, unsigned long size)
-{
- return 1;
+ return 0;
}
-#endif
void __attribute__((weak)) unxlate_dev_mem_ptr(unsigned long phys, void *addr)
{
@@ -151,11 +148,13 @@ static ssize_t read_mem(struct file * fi
while (count > 0) {
unsigned long remaining;
+ int err;
sz = size_inside_page(p, count);
- if (!range_is_allowed(p >> PAGE_SHIFT, count))
- return -EPERM;
+ err = devmem_check_pfn_range(p >> PAGE_SHIFT, count);
+ if (err)
+ return err;
/*
* On ia64 if a page has been mapped somewhere as
@@ -185,9 +184,10 @@ static ssize_t write_mem(struct file * f
size_t count, loff_t *ppos)
{
unsigned long p = *ppos;
- ssize_t written, sz;
unsigned long copied;
+ ssize_t written, sz;
void *ptr;
+ int err;
if (!valid_phys_addr_range(p, count))
return -EFAULT;
@@ -209,8 +209,9 @@ static ssize_t write_mem(struct file * f
while (count > 0) {
sz = size_inside_page(p, count);
- if (!range_is_allowed(p >> PAGE_SHIFT, sz))
- return -EPERM;
+ err = devmem_check_pfn_range(p >> PAGE_SHIFT, sz);
+ if (err)
+ return err;
/*
* On ia64 if a page has been mapped somewhere as
@@ -298,6 +299,7 @@ static struct vm_operations_struct mmap_
static int mmap_mem(struct file * file, struct vm_area_struct * vma)
{
size_t size = vma->vm_end - vma->vm_start;
+ int err;
if (!valid_mmap_phys_addr_range(vma->vm_pgoff, size))
return -EINVAL;
@@ -305,8 +307,9 @@ static int mmap_mem(struct file * file,
if (!private_mapping_ok(vma))
return -ENOSYS;
- if (!range_is_allowed(vma->vm_pgoff, size))
- return -EPERM;
+ err = devmem_check_pfn_range(vma->vm_pgoff, size);
+ if (err)
+ return err;
if (!phys_mem_access_prot_allowed(file, vma->vm_pgoff, size,
&vma->vm_page_prot))
--
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2009-09-16 3:08 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-09-16 3:00 [PATCH 0/4] /proc/kmem fixes and hwpoison bits v3 Wu Fengguang
2009-09-16 3:00 ` [PATCH 1/4] devmem: fix kmem write bug on memory holes Wu Fengguang
2009-09-16 3:00 ` [PATCH 2/4] devmem: check vmalloc address on kmem read/write Wu Fengguang
2009-09-16 3:00 ` [PATCH 3/4] HWPOISON: prevent /dev/kmem users from accessing hwpoison pages Wu Fengguang
2009-09-16 3:00 ` [PATCH 4/4] HWPOISON: stop /dev/mem " Wu Fengguang
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox