From: Andi Kleen <ak@suse.de>

On i386 and most other ports kern_addr_valid is hardcoded to 1.

This works fine as long as only mapped areas are accessed.  When you have
something partially mapped in the kclist it is possible that start points
to an unmapped address.  The correct behaviour in this case is to zero the
user space.

copy_to_user usually even checks for exceptions on both source and
destination, but it does not zero the destination in this case and worse
results in EFAULT, which is user visible.

This patch just tries to clear_user in this case again to actually zero the
user data and catch real user side EFAULTs.

Another way to fix this is to have kern_addr_valid do a real page table
lookup (I did that on AMD64), but having this fallback is a bit more
reliable in case there is a race somewhere.

On i386 it could happen for example if the direct space to max_low_pfn
contains something unmapped.  This normally isn't the case, but e.g.  the
slab debugging patches in -mm* do this so it's better to handle it.



 fs/proc/kcore.c |   16 ++++++++++++++--
 1 files changed, 14 insertions(+), 2 deletions(-)

diff -puN fs/proc/kcore.c~proc-kcore-handle-unmapped-areas fs/proc/kcore.c
--- 25/fs/proc/kcore.c~proc-kcore-handle-unmapped-areas	2003-06-17 09:46:23.000000000 -0700
+++ 25-akpm/fs/proc/kcore.c	2003-06-17 09:48:10.000000000 -0700
@@ -451,8 +451,20 @@ static ssize_t read_kcore(struct file *f
 			kfree(elf_buf);
 		} else {
 			if (kern_addr_valid(start)) {
-				if (copy_to_user(buffer, (char *)start, tsz))
-					return -EFAULT;
+				unsigned long n;
+
+				n = copy_to_user(buffer, (char *)start, tsz);
+				/*
+				 * We cannot distingush between fault on source
+				 * and fault on destination. When this happens
+				 * we clear too and hope it will trigger the
+				 * EFAULT again.
+				 */
+				if (n) { 
+					if (clear_user(buffer + tsz - n,
+								tsz - n))
+						return -EFAULT;
+				}
 			} else {
 				if (clear_user(buffer, tsz))
 					return -EFAULT;

_