[parisc-linux] kernel BUG at mm/mmap.c:1990 [PATCH attached]

Helge Deller deller at gmx.de
Wed Dec 13 14:50:43 MST 2006


On Tuesday 12 December 2006 02:14, Kyle McMartin wrote:
> On Mon, Dec 11, 2006 at 11:38:13PM +0100, Helge Deller wrote:
> > Maybe someone has an idea ?
> > 
> > The "adjtimex02" test from the Linux Test Project (http://ltp.sf.net) seems to pass all test, but triggers a kernel BUG in mm/mmap.c:1990 when exiting.
> > strace is attached below.
> 
> iirc this only bites on 32bit kernels.
> 
> This is what Jeff is referring to:
> /*
>  * Testcase reduced from ltp, adjtimex02
>  *
>  * 1) adjtimex(2) fails with errno set to EFAULT if buf does
>  *	   not point to writable memory
>  */
> [...]

The following patch is a first draft which fixes the LTP crashes. It still includes debugging info...
I assume the main problem is, that get_user() and put_user() does not do any memory region checking at all.
I think this is wrong (although the fault handler may have catched most of the wrong ones).

I know my implementation of the function access_ok() is wrong.
I tried and looked at the other arch implementations, but I didn't found an easy one. But I'm sure there is one, and hopefully someone here can point me to a better/correct implementation...?

Comments ?

Helge

diff --git a/arch/parisc/lib/memcpy.c b/arch/parisc/lib/memcpy.c
index 5575e41..cd8b657 100644
--- a/arch/parisc/lib/memcpy.c
+++ b/arch/parisc/lib/memcpy.c
@@ -488,20 +488,30 @@ handle_store_error:
 #ifdef __KERNEL__
 unsigned long copy_to_user(void __user *dst, const void *src, unsigned long len)
 {
-	mtsp(get_kernel_space(), 1);
-	mtsp(get_user_space(), 2);
-	return pa_memcpy((void __force *)dst, src, len);
+	BUG_ON((long) len < 0);
+	if (access_ok(VERIFY_WRITE, dst, len)) {
+		mtsp(get_kernel_space(), 1);
+		mtsp(get_user_space(), 2);
+		len = pa_memcpy((void __force *)dst, src, len);
+	};
+	return len;
 }
 
 unsigned long copy_from_user(void *dst, const void __user *src, unsigned long len)
 {
-	mtsp(get_user_space(), 1);
-	mtsp(get_kernel_space(), 2);
-	return pa_memcpy(dst, (void __force *)src, len);
+	BUG_ON((long) len < 0);
+	if (access_ok(VERIFY_READ, src, len)) {
+		mtsp(get_user_space(), 1);
+		mtsp(get_kernel_space(), 2);
+		len = pa_memcpy(dst, (void __force *)src, len);
+	} else
+		memset(dst, 0, len);
+	return len;
 }
 
 unsigned long copy_in_user(void __user *dst, const void __user *src, unsigned long len)
 {
+	BUG_ON((long) len < 0);
 	mtsp(get_user_space(), 1);
 	mtsp(get_user_space(), 2);
 	return pa_memcpy((void __force *)dst, (void __force *)src, len);
diff --git a/include/asm-parisc/uaccess.h b/include/asm-parisc/uaccess.h
index d973e8b..b265d2b 100644
--- a/include/asm-parisc/uaccess.h
+++ b/include/asm-parisc/uaccess.h
@@ -8,6 +8,7 @@
 #include <asm/page.h>
 #include <asm/system.h>
 #include <asm/cache.h>
+#include <asm/io.h>
 #include <asm-generic/uaccess.h>
 
 #define VERIFY_READ 0
@@ -37,23 +38,30 @@ extern int __put_user_bad(void);
 static inline long access_ok(int type, const void __user * addr,
 		unsigned long size)
 {
-	return 1;
+	unsigned long a = (unsigned long __force) addr;
+	long ok;
+	ok = (a < F_EXTEND(0xfff00000));
+	if (unlikely(!ok)) {
+		printk(KERN_ERR "%s: addr=%p len=%lx \n", __FUNCTION__, addr, size);
+		show_stack(NULL,NULL);
+	}
+	return (ok);
 }
 
-#define put_user __put_user
-#define get_user __get_user
 
-#if BITS_PER_LONG == 32
+#if !defined(__LP64__)
 #define LDD_KERNEL(ptr)		__get_kernel_bad();
 #define LDD_USER(ptr)		__get_user_bad();
 #define STD_KERNEL(x, ptr)	__put_kernel_asm64(x,ptr)
 #define STD_USER(x, ptr)	__put_user_asm64(x,ptr)
+#define WORD_DWORD		" .word "
 #else
-#define LDD_KERNEL(ptr) __get_kernel_asm("ldd",ptr)
-#define LDD_USER(ptr) __get_user_asm("ldd",ptr)
-#define STD_KERNEL(x, ptr) __put_kernel_asm("std",x,ptr)
-#define STD_USER(x, ptr) __put_user_asm("std",x,ptr)
-#endif
+#define LDD_KERNEL(ptr)		__get_kernel_asm("ldd",ptr)
+#define LDD_USER(ptr)		__get_user_asm("ldd",ptr)
+#define STD_KERNEL(x, ptr)	__put_kernel_asm("std",x,ptr)
+#define STD_USER(x, ptr)	__put_user_asm("std",x,ptr)
+#define WORD_DWORD		" .dword "
+#endif /* !__LP64__ */
 
 /*
  * The exception table contains two values: the first is an address
@@ -104,11 +112,10 @@ struct exception_data {
 	__gu_err;                                       \
 })
 
-#ifdef __LP64__
 #define __get_kernel_asm(ldx,ptr)                       \
 	__asm__("\n1:\t" ldx "\t0(%2),%0\n"             \
 		"\t.section __ex_table,\"aw\"\n"        \
-		"\t.dword\t1b,fixup_get_user_skip_1\n"	\
+		"\t" WORD_DWORD "\t1b,fixup_get_user_skip_1\n"	\
 		"\t.previous"                          	\
 		: "=r"(__gu_val), "=r"(__gu_err)        \
 		: "r"(ptr), "1"(__gu_err)		\
@@ -117,30 +124,12 @@ struct exception_data {
 #define __get_user_asm(ldx,ptr)                         \
 	__asm__("\n1:\t" ldx "\t0(%%sr3,%2),%0\n"       \
 		"\t.section __ex_table,\"aw\"\n"	\
-		"\t.dword\t1b,fixup_get_user_skip_1\n"	\
+		"\t" WORD_DWORD "\t1b,fixup_get_user_skip_1\n"	\
 		"\t.previous"				\
 		: "=r"(__gu_val), "=r"(__gu_err)        \
 		: "r"(ptr), "1"(__gu_err)		\
 		: "r1");
-#else
-#define __get_kernel_asm(ldx,ptr)                       \
-	__asm__("\n1:\t" ldx "\t0(%2),%0\n"             \
-		"\t.section __ex_table,\"aw\"\n"        \
-		"\t.word\t1b,fixup_get_user_skip_1\n"	\
-		"\t.previous"                          	\
-		: "=r"(__gu_val), "=r"(__gu_err)        \
-		: "r"(ptr), "1"(__gu_err)		\
-		: "r1");
 
-#define __get_user_asm(ldx,ptr)                         \
-	__asm__("\n1:\t" ldx "\t0(%%sr3,%2),%0\n"       \
-		"\t.section __ex_table,\"aw\"\n"	\
-		 "\t.word\t1b,fixup_get_user_skip_1\n"	\
-		 "\t.previous"                          \
-		: "=r"(__gu_val), "=r"(__gu_err)        \
-		: "r"(ptr), "1"(__gu_err)		\
-		: "r1");
-#endif /* !__LP64__ */
 
 #define __put_user(x,ptr)                                       \
 ({								\
@@ -179,12 +168,11 @@ struct exception_data {
  * r8/r9 are already listed as err/val.
  */
 
-#ifdef __LP64__
 #define __put_kernel_asm(stx,x,ptr)                         \
 	__asm__ __volatile__ (                              \
 		"\n1:\t" stx "\t%2,0(%1)\n"                 \
 		"\t.section __ex_table,\"aw\"\n"            \
-		"\t.dword\t1b,fixup_put_user_skip_1\n"	    \
+		"\t" WORD_DWORD "\t1b,fixup_put_user_skip_1\n"	    \
 		"\t.previous"                               \
 		: "=r"(__pu_err)                            \
 		: "r"(ptr), "r"(x), "0"(__pu_err)	    \
@@ -194,36 +182,18 @@ struct exception_data {
 	__asm__ __volatile__ (                              \
 		"\n1:\t" stx "\t%2,0(%%sr3,%1)\n"           \
 		"\t.section __ex_table,\"aw\"\n"            \
-		 "\t.dword\t1b,fixup_put_user_skip_1\n"	    \
-		 "\t.previous"                              \
-		: "=r"(__pu_err)                            \
-		: "r"(ptr), "r"(x), "0"(__pu_err)	    \
-		: "r1")
-#else
-#define __put_kernel_asm(stx,x,ptr)                         \
-	__asm__ __volatile__ (                              \
-		"\n1:\t" stx "\t%2,0(%1)\n"                 \
-		"\t.section __ex_table,\"aw\"\n"            \
-		 "\t.word\t1b,fixup_put_user_skip_1\n"	    \
+		 "\t" WORD_DWORD "\t1b,fixup_put_user_skip_1\n"	    \
 		 "\t.previous"                              \
 		: "=r"(__pu_err)                            \
 		: "r"(ptr), "r"(x), "0"(__pu_err)	    \
 		: "r1")
 
-#define __put_user_asm(stx,x,ptr)                           \
-	__asm__ __volatile__ (                              \
-		"\n1:\t" stx "\t%2,0(%%sr3,%1)\n"           \
-		"\t.section __ex_table,\"aw\"\n"            \
-		 "\t.word\t1b,fixup_put_user_skip_1\n"      \
-		 "\t.previous"                              \
-		: "=r"(__pu_err)                            \
-		: "r"(ptr), "r"(x), "0"(__pu_err)	    \
-		: "r1")
+#if !defined(__LP64__)
 
-#define __put_kernel_asm64(__val,ptr) do {		    	    \
-	u64 __val64 = (u64)(__val);				    \
-	u32 hi = (__val64) >> 32;					    \
-	u32 lo = (__val64) & 0xffffffff;				    \
+#define __put_kernel_asm64(__val,ptr) do {	    	    \
+	u64 __val64 = (u64)(__val);			    \
+	u32 hi = (__val64) >> 32;			    \
+	u32 lo = (__val64) & 0xffffffff;		    \
 	__asm__ __volatile__ (				    \
 		"\n1:\tstw %2,0(%1)\n"			    \
 		"\n2:\tstw %3,4(%1)\n"			    \
@@ -255,6 +225,26 @@ struct exception_data {
 #endif /* !__LP64__ */
 
 
+/* Uh, these should become the main single-value transfer routines..
+ * They automatically use the right size if we just have the right
+ * pointer type..
+ *
+ * This gets kind of ugly. We want to return _two_ values in "get_user()"
+ * and yet we don't want to do any pointers, because that is too much
+ * of a performance impact. Thus we have a few rather ugly macros here,
+ * and hide all the ugliness from the user.
+ */
+#define put_user(x,ptr) ({				\
+	__chk_user_ptr(ptr);				\
+	likely(access_ok(0,ptr,sizeof(*(ptr)))) ?	\
+	__put_user(x,ptr) : -EFAULT; })
+
+#define get_user(x,ptr) ({				\
+	__chk_user_ptr(ptr);				\
+	likely(access_ok(0,ptr,sizeof(*(ptr)))) ?	\
+	__get_user(x,ptr) : ({ x=0; -EFAULT;});  })
+
+
 /*
  * Complex access routines -- external declarations
  */



More information about the parisc-linux mailing list