Skip to content

Commit 8404663

Browse files
author
Russell King
committed
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: Catalin Marinas <catalin.marinas@arm.com> Signed-off-by: Will Deacon <will.deacon@arm.com> Cc: stable@vger.kernel.org Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
1 parent 2b2040a commit 8404663

File tree

4 files changed

+56
-21
lines changed

4 files changed

+56
-21
lines changed

Diff for: arch/arm/include/asm/assembler.h

+8
Original file line numberDiff line numberDiff line change
@@ -320,4 +320,12 @@
320320
.size \name , . - \name
321321
.endm
322322

323+
.macro check_uaccess, addr:req, size:req, limit:req, tmp:req, bad:req
324+
#ifndef CONFIG_CPU_USE_DOMAINS
325+
adds \tmp, \addr, #\size - 1
326+
sbcccs \tmp, \tmp, \limit
327+
bcs \bad
328+
#endif
329+
.endm
330+
323331
#endif /* __ASM_ASSEMBLER_H__ */

Diff for: arch/arm/include/asm/uaccess.h

+27-13
Original file line numberDiff line numberDiff line change
@@ -101,28 +101,39 @@ extern int __get_user_1(void *);
101101
extern int __get_user_2(void *);
102102
extern int __get_user_4(void *);
103103

104-
#define __get_user_x(__r2,__p,__e,__s,__i...) \
104+
#define __GUP_CLOBBER_1 "lr", "cc"
105+
#ifdef CONFIG_CPU_USE_DOMAINS
106+
#define __GUP_CLOBBER_2 "ip", "lr", "cc"
107+
#else
108+
#define __GUP_CLOBBER_2 "lr", "cc"
109+
#endif
110+
#define __GUP_CLOBBER_4 "lr", "cc"
111+
112+
#define __get_user_x(__r2,__p,__e,__l,__s) \
105113
__asm__ __volatile__ ( \
106114
__asmeq("%0", "r0") __asmeq("%1", "r2") \
115+
__asmeq("%3", "r1") \
107116
"bl __get_user_" #__s \
108117
: "=&r" (__e), "=r" (__r2) \
109-
: "0" (__p) \
110-
: __i, "cc")
118+
: "0" (__p), "r" (__l) \
119+
: __GUP_CLOBBER_##__s)
111120

112121
#define get_user(x,p) \
113122
({ \
123+
unsigned long __limit = current_thread_info()->addr_limit - 1; \
114124
register const typeof(*(p)) __user *__p asm("r0") = (p);\
115125
register unsigned long __r2 asm("r2"); \
126+
register unsigned long __l asm("r1") = __limit; \
116127
register int __e asm("r0"); \
117128
switch (sizeof(*(__p))) { \
118129
case 1: \
119-
__get_user_x(__r2, __p, __e, 1, "lr"); \
120-
break; \
130+
__get_user_x(__r2, __p, __e, __l, 1); \
131+
break; \
121132
case 2: \
122-
__get_user_x(__r2, __p, __e, 2, "r3", "lr"); \
133+
__get_user_x(__r2, __p, __e, __l, 2); \
123134
break; \
124135
case 4: \
125-
__get_user_x(__r2, __p, __e, 4, "lr"); \
136+
__get_user_x(__r2, __p, __e, __l, 4); \
126137
break; \
127138
default: __e = __get_user_bad(); break; \
128139
} \
@@ -135,31 +146,34 @@ extern int __put_user_2(void *, unsigned int);
135146
extern int __put_user_4(void *, unsigned int);
136147
extern int __put_user_8(void *, unsigned long long);
137148

138-
#define __put_user_x(__r2,__p,__e,__s) \
149+
#define __put_user_x(__r2,__p,__e,__l,__s) \
139150
__asm__ __volatile__ ( \
140151
__asmeq("%0", "r0") __asmeq("%2", "r2") \
152+
__asmeq("%3", "r1") \
141153
"bl __put_user_" #__s \
142154
: "=&r" (__e) \
143-
: "0" (__p), "r" (__r2) \
155+
: "0" (__p), "r" (__r2), "r" (__l) \
144156
: "ip", "lr", "cc")
145157

146158
#define put_user(x,p) \
147159
({ \
160+
unsigned long __limit = current_thread_info()->addr_limit - 1; \
148161
register const typeof(*(p)) __r2 asm("r2") = (x); \
149162
register const typeof(*(p)) __user *__p asm("r0") = (p);\
163+
register unsigned long __l asm("r1") = __limit; \
150164
register int __e asm("r0"); \
151165
switch (sizeof(*(__p))) { \
152166
case 1: \
153-
__put_user_x(__r2, __p, __e, 1); \
167+
__put_user_x(__r2, __p, __e, __l, 1); \
154168
break; \
155169
case 2: \
156-
__put_user_x(__r2, __p, __e, 2); \
170+
__put_user_x(__r2, __p, __e, __l, 2); \
157171
break; \
158172
case 4: \
159-
__put_user_x(__r2, __p, __e, 4); \
173+
__put_user_x(__r2, __p, __e, __l, 4); \
160174
break; \
161175
case 8: \
162-
__put_user_x(__r2, __p, __e, 8); \
176+
__put_user_x(__r2, __p, __e, __l, 8); \
163177
break; \
164178
default: __e = __put_user_bad(); break; \
165179
} \

Diff for: arch/arm/lib/getuser.S

+15-8
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,9 @@
1616
* __get_user_X
1717
*
1818
* Inputs: r0 contains the address
19+
* r1 contains the address limit, which must be preserved
1920
* Outputs: r0 is the error code
20-
* r2, r3 contains the zero-extended value
21+
* r2 contains the zero-extended value
2122
* lr corrupted
2223
*
2324
* No other registers must be altered. (see <asm/uaccess.h>
@@ -27,33 +28,39 @@
2728
* Note also that it is intended that __get_user_bad is not global.
2829
*/
2930
#include <linux/linkage.h>
31+
#include <asm/assembler.h>
3032
#include <asm/errno.h>
3133
#include <asm/domain.h>
3234

3335
ENTRY(__get_user_1)
36+
check_uaccess r0, 1, r1, r2, __get_user_bad
3437
1: TUSER(ldrb) r2, [r0]
3538
mov r0, #0
3639
mov pc, lr
3740
ENDPROC(__get_user_1)
3841

3942
ENTRY(__get_user_2)
40-
#ifdef CONFIG_THUMB2_KERNEL
41-
2: TUSER(ldrb) r2, [r0]
42-
3: TUSER(ldrb) r3, [r0, #1]
43+
check_uaccess r0, 2, r1, r2, __get_user_bad
44+
#ifdef CONFIG_CPU_USE_DOMAINS
45+
rb .req ip
46+
2: ldrbt r2, [r0], #1
47+
3: ldrbt rb, [r0], #0
4348
#else
44-
2: TUSER(ldrb) r2, [r0], #1
45-
3: TUSER(ldrb) r3, [r0]
49+
rb .req r0
50+
2: ldrb r2, [r0]
51+
3: ldrb rb, [r0, #1]
4652
#endif
4753
#ifndef __ARMEB__
48-
orr r2, r2, r3, lsl #8
54+
orr r2, r2, rb, lsl #8
4955
#else
50-
orr r2, r3, r2, lsl #8
56+
orr r2, rb, r2, lsl #8
5157
#endif
5258
mov r0, #0
5359
mov pc, lr
5460
ENDPROC(__get_user_2)
5561

5662
ENTRY(__get_user_4)
63+
check_uaccess r0, 4, r1, r2, __get_user_bad
5764
4: TUSER(ldr) r2, [r0]
5865
mov r0, #0
5966
mov pc, lr

Diff for: arch/arm/lib/putuser.S

+6
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
* __put_user_X
1717
*
1818
* Inputs: r0 contains the address
19+
* r1 contains the address limit, which must be preserved
1920
* r2, r3 contains the value
2021
* Outputs: r0 is the error code
2122
* lr corrupted
@@ -27,16 +28,19 @@
2728
* Note also that it is intended that __put_user_bad is not global.
2829
*/
2930
#include <linux/linkage.h>
31+
#include <asm/assembler.h>
3032
#include <asm/errno.h>
3133
#include <asm/domain.h>
3234

3335
ENTRY(__put_user_1)
36+
check_uaccess r0, 1, r1, ip, __put_user_bad
3437
1: TUSER(strb) r2, [r0]
3538
mov r0, #0
3639
mov pc, lr
3740
ENDPROC(__put_user_1)
3841

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

6266
ENTRY(__put_user_4)
67+
check_uaccess r0, 4, r1, ip, __put_user_bad
6368
4: TUSER(str) r2, [r0]
6469
mov r0, #0
6570
mov pc, lr
6671
ENDPROC(__put_user_4)
6772

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

0 commit comments

Comments
 (0)