[PATCH 3.2 176/185] ARM: 7527/1: uaccess: explicitly check __user pointer when !CPU_USE_DOMAINS
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
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)