[PATCH 3.2 176/185] ARM: 7527/1: uaccess: explicitly check __user pointer when !CPU_USE_DOMAINS

2013-12-28 Thread Ben Hutchings
3.2.54-rc1 review patch.  If anyone has any objections, please let me know.

--

From: Russell King 

commit 8404663f81d212918ff85f493649a7991209fa04 upstream.

The {get,put}_user macros don't perform range checking on the provided
__user address when !CPU_HAS_DOMAINS.

This patch reworks the out-of-line assembly accessors to check the user
address against a specified limit, returning -EFAULT if is is out of
range.

[will: changed get_user register allocation to match put_user]
[rmk: fixed building on older ARM architectures]

Reported-by: Catalin Marinas 
Signed-off-by: Will Deacon 
Signed-off-by: Russell King 
[bwh: Backported to 3.2: TUSER() was called T()]
Signed-off-by: Ben Hutchings 
---
 arch/arm/include/asm/assembler.h |  8 
 arch/arm/include/asm/uaccess.h   | 40 +++-
 arch/arm/lib/getuser.S   | 23 +++
 arch/arm/lib/putuser.S   |  6 ++
 4 files changed, 56 insertions(+), 21 deletions(-)

--- a/arch/arm/include/asm/assembler.h
+++ b/arch/arm/include/asm/assembler.h
@@ -307,4 +307,12 @@
.size \name , . - \name
.endm
 
+   .macro check_uaccess, addr:req, size:req, limit:req, tmp:req, bad:req
+#ifndef CONFIG_CPU_USE_DOMAINS
+   adds\tmp, \addr, #\size - 1
+   sbcccs  \tmp, \tmp, \limit
+   bcs \bad
+#endif
+   .endm
+
 #endif /* __ASM_ASSEMBLER_H__ */
--- a/arch/arm/include/asm/uaccess.h
+++ b/arch/arm/include/asm/uaccess.h
@@ -101,28 +101,39 @@ extern int __get_user_1(void *);
 extern int __get_user_2(void *);
 extern int __get_user_4(void *);
 
-#define __get_user_x(__r2,__p,__e,__s,__i...)  \
+#define __GUP_CLOBBER_1"lr", "cc"
+#ifdef CONFIG_CPU_USE_DOMAINS
+#define __GUP_CLOBBER_2"ip", "lr", "cc"
+#else
+#define __GUP_CLOBBER_2 "lr", "cc"
+#endif
+#define __GUP_CLOBBER_4"lr", "cc"
+
+#define __get_user_x(__r2,__p,__e,__l,__s) \
   __asm__ __volatile__ (   \
__asmeq("%0", "r0") __asmeq("%1", "r2") \
+   __asmeq("%3", "r1") \
"bl __get_user_" #__s   \
: "=" (__e), "=r" (__r2)  \
-   : "0" (__p) \
-   : __i, "cc")
+   : "0" (__p), "r" (__l)  \
+   : __GUP_CLOBBER_##__s)
 
 #define get_user(x,p)  \
({  \
+   unsigned long __limit = current_thread_info()->addr_limit - 1; \
register const typeof(*(p)) __user *__p asm("r0") = (p);\
register unsigned long __r2 asm("r2");  \
+   register unsigned long __l asm("r1") = __limit; \
register int __e asm("r0"); \
switch (sizeof(*(__p))) {   \
case 1: \
-   __get_user_x(__r2, __p, __e, 1, "lr");  \
-   break;  \
+   __get_user_x(__r2, __p, __e, __l, 1);   \
+   break;  \
case 2: \
-   __get_user_x(__r2, __p, __e, 2, "r3", "lr");\
+   __get_user_x(__r2, __p, __e, __l, 2);   \
break;  \
case 4: \
-   __get_user_x(__r2, __p, __e, 4, "lr");  \
+   __get_user_x(__r2, __p, __e, __l, 4);   \
break;  \
default: __e = __get_user_bad(); break; \
}   \
@@ -135,31 +146,34 @@ extern int __put_user_2(void *, unsigned
 extern int __put_user_4(void *, unsigned int);
 extern int __put_user_8(void *, unsigned long long);
 
-#define __put_user_x(__r2,__p,__e,__s) \
+#define __put_user_x(__r2,__p,__e,__l,__s) \
   __asm__ __volatile__ (   \
__asmeq("%0", "r0") __asmeq("%2", "r2") \
+   __asmeq("%3", "r1") \
"bl __put_user_" #__s   \
: "=" (__e)   \
-   : "0" (__p), "r" 

[PATCH 3.2 176/185] ARM: 7527/1: uaccess: explicitly check __user pointer when !CPU_USE_DOMAINS

2013-12-28 Thread Ben Hutchings
3.2.54-rc1 review patch.  If anyone has any objections, please let me know.

--

From: Russell King rmk+ker...@arm.linux.org.uk

commit 8404663f81d212918ff85f493649a7991209fa04 upstream.

The {get,put}_user macros don't perform range checking on the provided
__user address when !CPU_HAS_DOMAINS.

This patch reworks the out-of-line assembly accessors to check the user
address against a specified limit, returning -EFAULT if is is out of
range.

[will: changed get_user register allocation to match put_user]
[rmk: fixed building on older ARM architectures]

Reported-by: Catalin Marinas catalin.mari...@arm.com
Signed-off-by: Will Deacon will.dea...@arm.com
Signed-off-by: Russell King rmk+ker...@arm.linux.org.uk
[bwh: Backported to 3.2: TUSER() was called T()]
Signed-off-by: Ben Hutchings b...@decadent.org.uk
---
 arch/arm/include/asm/assembler.h |  8 
 arch/arm/include/asm/uaccess.h   | 40 +++-
 arch/arm/lib/getuser.S   | 23 +++
 arch/arm/lib/putuser.S   |  6 ++
 4 files changed, 56 insertions(+), 21 deletions(-)

--- a/arch/arm/include/asm/assembler.h
+++ b/arch/arm/include/asm/assembler.h
@@ -307,4 +307,12 @@
.size \name , . - \name
.endm
 
+   .macro check_uaccess, addr:req, size:req, limit:req, tmp:req, bad:req
+#ifndef CONFIG_CPU_USE_DOMAINS
+   adds\tmp, \addr, #\size - 1
+   sbcccs  \tmp, \tmp, \limit
+   bcs \bad
+#endif
+   .endm
+
 #endif /* __ASM_ASSEMBLER_H__ */
--- a/arch/arm/include/asm/uaccess.h
+++ b/arch/arm/include/asm/uaccess.h
@@ -101,28 +101,39 @@ extern int __get_user_1(void *);
 extern int __get_user_2(void *);
 extern int __get_user_4(void *);
 
-#define __get_user_x(__r2,__p,__e,__s,__i...)  \
+#define __GUP_CLOBBER_1lr, cc
+#ifdef CONFIG_CPU_USE_DOMAINS
+#define __GUP_CLOBBER_2ip, lr, cc
+#else
+#define __GUP_CLOBBER_2 lr, cc
+#endif
+#define __GUP_CLOBBER_4lr, cc
+
+#define __get_user_x(__r2,__p,__e,__l,__s) \
   __asm__ __volatile__ (   \
__asmeq(%0, r0) __asmeq(%1, r2) \
+   __asmeq(%3, r1) \
bl __get_user_ #__s   \
: =r (__e), =r (__r2)  \
-   : 0 (__p) \
-   : __i, cc)
+   : 0 (__p), r (__l)  \
+   : __GUP_CLOBBER_##__s)
 
 #define get_user(x,p)  \
({  \
+   unsigned long __limit = current_thread_info()-addr_limit - 1; \
register const typeof(*(p)) __user *__p asm(r0) = (p);\
register unsigned long __r2 asm(r2);  \
+   register unsigned long __l asm(r1) = __limit; \
register int __e asm(r0); \
switch (sizeof(*(__p))) {   \
case 1: \
-   __get_user_x(__r2, __p, __e, 1, lr);  \
-   break;  \
+   __get_user_x(__r2, __p, __e, __l, 1);   \
+   break;  \
case 2: \
-   __get_user_x(__r2, __p, __e, 2, r3, lr);\
+   __get_user_x(__r2, __p, __e, __l, 2);   \
break;  \
case 4: \
-   __get_user_x(__r2, __p, __e, 4, lr);  \
+   __get_user_x(__r2, __p, __e, __l, 4);   \
break;  \
default: __e = __get_user_bad(); break; \
}   \
@@ -135,31 +146,34 @@ extern int __put_user_2(void *, unsigned
 extern int __put_user_4(void *, unsigned int);
 extern int __put_user_8(void *, unsigned long long);
 
-#define __put_user_x(__r2,__p,__e,__s) \
+#define __put_user_x(__r2,__p,__e,__l,__s) \
   __asm__ __volatile__ (   \
__asmeq(%0, r0) __asmeq(%2, r2) \
+   __asmeq(%3, r1) \
bl __put_user_ #__s   \
: =r (__e)