Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8404663f authored by Russell King's avatar Russell King
Browse files

ARM: 7527/1: uaccess: explicitly check __user pointer when !CPU_USE_DOMAINS



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: default avatarCatalin Marinas <catalin.marinas@arm.com>
Signed-off-by: default avatarWill Deacon <will.deacon@arm.com>
Cc: stable@vger.kernel.org
Signed-off-by: default avatarRussell King <rmk+kernel@arm.linux.org.uk>
parent 2b2040af
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -320,4 +320,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__ */
+27 −13
Original line number Diff line number Diff line
@@ -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				\
		: "=&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");		\
			__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 int);
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)						\
		: "0" (__p), "r" (__r2)					\
		: "0" (__p), "r" (__r2), "r" (__l)			\
		: "ip", "lr", "cc")

#define put_user(x,p)							\
	({								\
		unsigned long __limit = current_thread_info()->addr_limit - 1; \
		register const typeof(*(p)) __r2 asm("r2") = (x);	\
		register const typeof(*(p)) __user *__p asm("r0") = (p);\
		register unsigned long __l asm("r1") = __limit;		\
		register int __e asm("r0");				\
		switch (sizeof(*(__p))) {				\
		case 1:							\
			__put_user_x(__r2, __p, __e, 1);		\
			__put_user_x(__r2, __p, __e, __l, 1);		\
			break;						\
		case 2:							\
			__put_user_x(__r2, __p, __e, 2);		\
			__put_user_x(__r2, __p, __e, __l, 2);		\
			break;						\
		case 4:							\
			__put_user_x(__r2, __p, __e, 4);		\
			__put_user_x(__r2, __p, __e, __l, 4);		\
			break;						\
		case 8:							\
			__put_user_x(__r2, __p, __e, 8);		\
			__put_user_x(__r2, __p, __e, __l, 8);		\
			break;						\
		default: __e = __put_user_bad(); break;			\
		}							\
+15 −8
Original line number Diff line number Diff line
@@ -16,8 +16,9 @@
 * __get_user_X
 *
 * Inputs:	r0 contains the address
 *		r1 contains the address limit, which must be preserved
 * Outputs:	r0 is the error code
 *		r2, r3 contains the zero-extended value
 *		r2 contains the zero-extended value
 *		lr corrupted
 *
 * No other registers must be altered.  (see <asm/uaccess.h>
@@ -27,33 +28,39 @@
 * Note also that it is intended that __get_user_bad is not global.
 */
#include <linux/linkage.h>
#include <asm/assembler.h>
#include <asm/errno.h>
#include <asm/domain.h>

ENTRY(__get_user_1)
	check_uaccess r0, 1, r1, r2, __get_user_bad
1: TUSER(ldrb)	r2, [r0]
	mov	r0, #0
	mov	pc, lr
ENDPROC(__get_user_1)

ENTRY(__get_user_2)
#ifdef CONFIG_THUMB2_KERNEL
2: TUSER(ldrb)	r2, [r0]
3: TUSER(ldrb)	r3, [r0, #1]
	check_uaccess r0, 2, r1, r2, __get_user_bad
#ifdef CONFIG_CPU_USE_DOMAINS
rb	.req	ip
2:	ldrbt	r2, [r0], #1
3:	ldrbt	rb, [r0], #0
#else
2: TUSER(ldrb)	r2, [r0], #1
3: TUSER(ldrb)	r3, [r0]
rb	.req	r0
2:	ldrb	r2, [r0]
3:	ldrb	rb, [r0, #1]
#endif
#ifndef __ARMEB__
	orr	r2, r2, r3, lsl #8
	orr	r2, r2, rb, lsl #8
#else
	orr	r2, r3, r2, lsl #8
	orr	r2, rb, r2, lsl #8
#endif
	mov	r0, #0
	mov	pc, lr
ENDPROC(__get_user_2)

ENTRY(__get_user_4)
	check_uaccess r0, 4, r1, r2, __get_user_bad
4: TUSER(ldr)	r2, [r0]
	mov	r0, #0
	mov	pc, lr
+6 −0
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@
 * __put_user_X
 *
 * Inputs:	r0 contains the address
 *		r1 contains the address limit, which must be preserved
 *		r2, r3 contains the value
 * Outputs:	r0 is the error code
 *		lr corrupted
@@ -27,16 +28,19 @@
 * Note also that it is intended that __put_user_bad is not global.
 */
#include <linux/linkage.h>
#include <asm/assembler.h>
#include <asm/errno.h>
#include <asm/domain.h>

ENTRY(__put_user_1)
	check_uaccess r0, 1, r1, ip, __put_user_bad
1: TUSER(strb)	r2, [r0]
	mov	r0, #0
	mov	pc, lr
ENDPROC(__put_user_1)

ENTRY(__put_user_2)
	check_uaccess r0, 2, r1, ip, __put_user_bad
	mov	ip, r2, lsr #8
#ifdef CONFIG_THUMB2_KERNEL
#ifndef __ARMEB__
@@ -60,12 +64,14 @@ ENTRY(__put_user_2)
ENDPROC(__put_user_2)

ENTRY(__put_user_4)
	check_uaccess r0, 4, r1, ip, __put_user_bad
4: TUSER(str)	r2, [r0]
	mov	r0, #0
	mov	pc, lr
ENDPROC(__put_user_4)

ENTRY(__put_user_8)
	check_uaccess r0, 8, r1, ip, __put_user_bad
#ifdef CONFIG_THUMB2_KERNEL
5: TUSER(str)	r2, [r0]
6: TUSER(str)	r3, [r0, #4]