rpms/kernel/F-11 devmem-check-vmalloc-address-on-kmem-read-write.patch, NONE, 1.1 devmem-fix-kmem-write-bug-on-memory-holes.patch, NONE, 1.1 devmem-introduce-size_inside_page.patch, NONE, 1.1 kernel.spec, 1.1808, 1.1809

Chuck Ebbert cebbert at fedoraproject.org
Fri Feb 5 18:18:33 UTC 2010


Author: cebbert

Update of /cvs/pkgs/rpms/kernel/F-11
In directory cvs1.fedora.phx.redhat.com:/tmp/cvs-serv1195

Modified Files:
	kernel.spec 
Added Files:
	devmem-check-vmalloc-address-on-kmem-read-write.patch 
	devmem-fix-kmem-write-bug-on-memory-holes.patch 
	devmem-introduce-size_inside_page.patch 
Log Message:
Backport three bug fixes for /dev/kmem

devmem-check-vmalloc-address-on-kmem-read-write.patch:
 mem.c |   28 ++++++++++++++++++----------
 1 file changed, 18 insertions(+), 10 deletions(-)

--- NEW FILE devmem-check-vmalloc-address-on-kmem-read-write.patch ---
From: KAMEZAWA Hiroyuki <kamezawa.hiroyu at jp.fujitsu.com>
Date: Tue, 2 Feb 2010 21:44:05 +0000 (-0800)
Subject: devmem: check vmalloc address on kmem read/write
X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=325fda71d0badc1073dc59f12a948f24ff05796a

[ cebbert at 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: KAMEZAWA Hiroyuki <kamezawa.hiroyu at jp.fujitsu.com>
Signed-off-by: Wu Fengguang <fengguang.wu at intel.com>
Cc: Greg Kroah-Hartman <gregkh at suse.de>
Cc: Hugh Dickins <hugh.dickins at tiscali.co.uk>
Cc: <stable at kernel.org>
Signed-off-by: Andrew Morton <akpm at linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds at linux-foundation.org>
---

diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index be832b6..1fd4b11 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,
 		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;
@@ -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 virtr = 0;
 	ssize_t written;
 	char * kbuf; /* k-addr because vwrite() takes vmlist_lock rwlock */
+	int err = 0;
 
 	if (p < (unsigned long) high_memory) {
 
@@ -540,13 +546,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)
-						break;
-					free_page((unsigned long)kbuf);
-					return -EFAULT;
+					err = -EFAULT;
+					break;
 				}
 			}
 			len = vwrite(kbuf, (char *)p, 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
 

devmem-fix-kmem-write-bug-on-memory-holes.patch:
 mem.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

--- NEW FILE devmem-fix-kmem-write-bug-on-memory-holes.patch ---
From: Wu Fengguang <fengguang.wu at intel.com>
Date: Tue, 2 Feb 2010 21:44:06 +0000 (-0800)
Subject: devmem: fix kmem write bug on memory holes
X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=c85e9a97c4102ce2e83112da850d838cfab5ab13

devmem: fix kmem write bug on memory holes

[ cebbert at redhat.com : backport to 2.6.32 ]

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.

Signed-off-by: Wu Fengguang <fengguang.wu at intel.com>
Cc: Andi Kleen <andi at firstfloor.org>
Cc: Benjamin Herrenschmidt <benh at kernel.crashing.org>
Cc: Christoph Lameter <cl at linux-foundation.org>
Cc: Ingo Molnar <mingo at elte.hu>
Cc: Tejun Heo <tj at kernel.org>
Cc: Nick Piggin <npiggin at suse.de>
Cc: KAMEZAWA Hiroyuki <kamezawa.hiroyu at jp.fujitsu.com>
Cc: <stable at kernel.org>
Signed-off-by: Andrew Morton <akpm at linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds at linux-foundation.org>
---

diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index 1fd4b11..48788db 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -555,7 +555,7 @@ static ssize_t write_kmem(struct file * file, const char __user * buf,
 					break;
 				}
 			}
-			len = vwrite(kbuf, (char *)p, len);
+			vwrite(kbuf, (char *)p, len);
 			count -= len;
 			buf += len;
 			virtr += len;

devmem-introduce-size_inside_page.patch:
 mem.c |   40 +++++++++++++++++-----------------------
 1 file changed, 17 insertions(+), 23 deletions(-)

--- NEW FILE devmem-introduce-size_inside_page.patch ---
From: Wu Fengguang <fengguang.wu at intel.com>
Date: Tue, 15 Dec 2009 01:58:07 +0000 (-0800)
Subject: /dev/mem: introduce size_inside_page()
X-Git-Tag: v2.6.33-rc1~263
X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=f222318e9c3a315723e3524fb9d6566b2430db44

/dev/mem: introduce size_inside_page()

[ cebbert at redhat.com : backport to 2.6.32 ]
[ subset of original patch, for just /dev/kmem ]

Introduce size_inside_page() to replace duplicate /dev/mem code.

Also apply it to /dev/kmem, whose alignment logic was buggy.

Signed-off-by: Wu Fengguang <fengguang.wu at intel.com>
Acked-by: Andi Kleen <ak at linux.intel.com>
Cc: Marcelo Tosatti <mtosatti at redhat.com>
Cc: Greg Kroah-Hartman <gregkh at suse.de>
Cc: Mark Brown <broonie at opensource.wolfsonmicro.com>
Cc: Johannes Berg <johannes at sipsolutions.net>
Cc: Avi Kivity <avi at qumranet.com>
Signed-off-by: Andrew Morton <akpm at linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds at linux-foundation.org>
---

diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index f0a9059..aaa9c24 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -35,6 +35,19 @@
 # include <linux/efi.h>
 #endif
 
+static inline unsigned long size_inside_page(unsigned long start,
+					     unsigned long size)
+{
+	unsigned long sz;
+
+	if (-start & (PAGE_SIZE - 1))
+		sz = -start & (PAGE_SIZE - 1);
+	else
+		sz = PAGE_SIZE;
+
+	return min_t(unsigned long, sz, size);
+}
+
 /*
  * Architectures vary in how they handle caching for addresses
  * outside of main memory.
@@ -428,15 +441,7 @@ static ssize_t read_kmem(struct file *file, char __user *buf,
 		}
 #endif
 		while (low_count > 0) {
-			/*
-			 * Handle first page in case it's not aligned
-			 */
-			if (-p & (PAGE_SIZE - 1))
-				sz = -p & (PAGE_SIZE - 1);
-			else
-				sz = PAGE_SIZE;
-
-			sz = min_t(unsigned long, sz, low_count);
+			sz = size_inside_page(p, low_count);
 
 			/*
 			 * On ia64 if a page has been mapped somewhere as
@@ -461,10 +466,8 @@ static ssize_t read_kmem(struct file *file, char __user *buf,
 		if (!kbuf)
 			return -ENOMEM;
 		while (count > 0) {
-			int len = count;
+			int len = size_inside_page(p, count);
 
-			if (len > PAGE_SIZE)
-				len = PAGE_SIZE;
 			len = vread(kbuf, (char *)p, len);
 			if (!len)
 				break;
@@ -509,15 +512,8 @@ do_write_kmem(void *p, unsigned long realp, const char __user * buf,
 
 	while (count > 0) {
 		char *ptr;
-		/*
-		 * Handle first page in case it's not aligned
-		 */
-		if (-realp & (PAGE_SIZE - 1))
-			sz = -realp & (PAGE_SIZE - 1);
-		else
-			sz = PAGE_SIZE;
 
-		sz = min_t(unsigned long, sz, count);
+		sz = size_inside_page(realp, count);
 
 		/*
 		 * On ia64 if a page has been mapped somewhere as
@@ -577,10 +573,8 @@ static ssize_t write_kmem(struct file * file, const char __user * buf,
 		if (!kbuf)
 			return wrote ? wrote : -ENOMEM;
 		while (count > 0) {
-			int len = count;
+			int len = size_inside_page(p, count);
 
-			if (len > PAGE_SIZE)
-				len = PAGE_SIZE;
 			if (len) {
 				written = copy_from_user(kbuf, buf, len);
 				if (written) {


Index: kernel.spec
===================================================================
RCS file: /cvs/pkgs/rpms/kernel/F-11/kernel.spec,v
retrieving revision 1.1808
retrieving revision 1.1809
diff -u -p -r1.1808 -r1.1809
--- kernel.spec	5 Feb 2010 00:49:37 -0000	1.1808
+++ kernel.spec	5 Feb 2010 18:18:33 -0000	1.1809
@@ -751,6 +751,11 @@ Patch12102: wmi-check-wmi-get-event-data
 Patch12301: fix-conntrack-bug-with-namespaces.patch
 Patch12302: prevent-runtime-conntrack-changes.patch
 
+# backport /dev/mem patches for -stable
+Patch20010: devmem-introduce-size_inside_page.patch
+Patch20020: devmem-check-vmalloc-address-on-kmem-read-write.patch
+Patch20030: devmem-fix-kmem-write-bug-on-memory-holes.patch
+
 #===============================================================================
 %endif
 
@@ -1373,6 +1378,11 @@ ApplyPatch wmi-check-wmi-get-event-data-
 ApplyPatch fix-conntrack-bug-with-namespaces.patch
 ApplyPatch prevent-runtime-conntrack-changes.patch
 
+# backport /dev/mem patches for -stable
+ApplyPatch devmem-introduce-size_inside_page.patch
+ApplyPatch devmem-check-vmalloc-address-on-kmem-read-write.patch
+ApplyPatch devmem-fix-kmem-write-bug-on-memory-holes.patch
+
 # END OF PATCH APPLICATIONS ====================================================
 
 %endif
@@ -2028,6 +2038,9 @@ fi
 # and build.
 
 %changelog
+* Fri Feb 05 2010 Chuck Ebbert <cebbert at redhat.com>  2.6.32.8-24.rc1
+- Backport three bug fixes for /dev/kmem
+
 * Thu Feb 04 2010 Chuck Ebbert <cebbert at redhat.com>  2.6.32.8-23.rc1
 - Copy DMAR fix for cantiga chipset from F-12
 - Disable DMAR by default: CONFIG_DMAR_DEFAULT_ON is not set



More information about the scm-commits mailing list