@@ -61,6 +61,19 @@ static inline unsigned long __untagged_addr_remote(struct mm_struct *mm, unsigne
61
61
#define __disable_user_access () \
62
62
__asm__ __volatile__ ("csrc sstatus, %0" : : "r" (SR_SUM) : "memory")
63
63
64
+ /*
65
+ * This is the smallest unsigned integer type that can fit a value
66
+ * (up to 'long long')
67
+ */
68
+ #define __inttype (x ) __typeof__( \
69
+ __typefits(x, char, \
70
+ __typefits(x, short, \
71
+ __typefits(x, int, \
72
+ __typefits(x, long, 0ULL)))))
73
+
74
+ #define __typefits (x , type , not ) \
75
+ __builtin_choose_expr(sizeof(x) <= sizeof(type), (unsigned type)0, not)
76
+
64
77
/*
65
78
* The exception table consists of pairs of addresses: the first is the
66
79
* address of an instruction that is allowed to fault, and the second is
@@ -83,27 +96,58 @@ static inline unsigned long __untagged_addr_remote(struct mm_struct *mm, unsigne
83
96
* call.
84
97
*/
85
98
86
- #define __get_user_asm (insn , x , ptr , err ) \
99
+ #ifdef CONFIG_CC_HAS_ASM_GOTO_OUTPUT
100
+ #define __get_user_asm (insn , x , ptr , label ) \
101
+ asm_goto_output( \
102
+ "1:\n" \
103
+ " " insn " %0, %1\n" \
104
+ _ASM_EXTABLE_UACCESS_ERR(1b, %l2, %0) \
105
+ : "=&r" (x) \
106
+ : "m" (*(ptr)) : : label)
107
+ #else /* !CONFIG_CC_HAS_ASM_GOTO_OUTPUT */
108
+ #define __get_user_asm (insn , x , ptr , label ) \
87
109
do { \
88
- __typeof__(x) __x ; \
110
+ long __gua_err = 0 ; \
89
111
__asm__ __volatile__ ( \
90
112
"1:\n" \
91
113
" " insn " %1, %2\n" \
92
114
"2:\n" \
93
115
_ASM_EXTABLE_UACCESS_ERR_ZERO(1b, 2b, %0, %1) \
94
- : "+r" (err ), "=&r" (__x ) \
116
+ : "+r" (__gua_err ), "=&r" (x ) \
95
117
: "m" (*(ptr))); \
96
- (x) = __x; \
118
+ if (__gua_err) \
119
+ goto label; \
97
120
} while (0)
121
+ #endif /* CONFIG_CC_HAS_ASM_GOTO_OUTPUT */
98
122
99
123
#ifdef CONFIG_64BIT
100
- #define __get_user_8 (x , ptr , err ) \
101
- __get_user_asm("ld", x, ptr, err )
124
+ #define __get_user_8 (x , ptr , label ) \
125
+ __get_user_asm("ld", x, ptr, label )
102
126
#else /* !CONFIG_64BIT */
103
- #define __get_user_8 (x , ptr , err ) \
127
+
128
+ #ifdef CONFIG_CC_HAS_ASM_GOTO_OUTPUT
129
+ #define __get_user_8 (x , ptr , label ) \
130
+ u32 __user *__ptr = (u32 __user *)(ptr); \
131
+ u32 __lo, __hi; \
132
+ asm_goto_output( \
133
+ "1:\n" \
134
+ " lw %0, %2\n" \
135
+ "2:\n" \
136
+ " lw %1, %3\n" \
137
+ _ASM_EXTABLE_UACCESS_ERR(1b, %l4, %0) \
138
+ _ASM_EXTABLE_UACCESS_ERR(2b, %l4, %0) \
139
+ : "=&r" (__lo), "=r" (__hi) \
140
+ : "m" (__ptr[__LSW]), "m" (__ptr[__MSW]) \
141
+ : : label); \
142
+ (x) = (__typeof__(x))((__typeof__((x) - (x)))( \
143
+ (((u64)__hi << 32) | __lo))); \
144
+
145
+ #else /* !CONFIG_CC_HAS_ASM_GOTO_OUTPUT */
146
+ #define __get_user_8 (x , ptr , label ) \
104
147
do { \
105
148
u32 __user *__ptr = (u32 __user *)(ptr); \
106
149
u32 __lo, __hi; \
150
+ long __gu8_err = 0; \
107
151
__asm__ __volatile__ ( \
108
152
"1:\n" \
109
153
" lw %1, %3\n" \
@@ -112,35 +156,51 @@ do { \
112
156
"3:\n" \
113
157
_ASM_EXTABLE_UACCESS_ERR_ZERO(1b, 3b, %0, %1) \
114
158
_ASM_EXTABLE_UACCESS_ERR_ZERO(2b, 3b, %0, %1) \
115
- : "+r" (err ), "=&r" (__lo), "=r" (__hi) \
159
+ : "+r" (__gu8_err ), "=&r" (__lo), "=r" (__hi) \
116
160
: "m" (__ptr[__LSW]), "m" (__ptr[__MSW])); \
117
- if (err) \
161
+ if (__gu8_err) { \
118
162
__hi = 0; \
119
- (x) = (__typeof__(x))((__typeof__((x)-(x)))( \
163
+ goto label; \
164
+ } \
165
+ (x) = (__typeof__(x))((__typeof__((x) - (x)))( \
120
166
(((u64)__hi << 32) | __lo))); \
121
167
} while (0)
168
+ #endif /* CONFIG_CC_HAS_ASM_GOTO_OUTPUT */
169
+
122
170
#endif /* CONFIG_64BIT */
123
171
124
- #define __get_user_nocheck (x , __gu_ptr , __gu_err ) \
172
+ #define __get_user_nocheck (x , __gu_ptr , label ) \
125
173
do { \
126
174
switch (sizeof(*__gu_ptr)) { \
127
175
case 1: \
128
- __get_user_asm("lb", (x), __gu_ptr, __gu_err ); \
176
+ __get_user_asm("lb", (x), __gu_ptr, label ); \
129
177
break; \
130
178
case 2: \
131
- __get_user_asm("lh", (x), __gu_ptr, __gu_err ); \
179
+ __get_user_asm("lh", (x), __gu_ptr, label ); \
132
180
break; \
133
181
case 4: \
134
- __get_user_asm("lw", (x), __gu_ptr, __gu_err ); \
182
+ __get_user_asm("lw", (x), __gu_ptr, label ); \
135
183
break; \
136
184
case 8: \
137
- __get_user_8((x), __gu_ptr, __gu_err); \
185
+ __get_user_8((x), __gu_ptr, label); \
138
186
break; \
139
187
default: \
140
188
BUILD_BUG(); \
141
189
} \
142
190
} while (0)
143
191
192
+ #define __get_user_error (x , ptr , err ) \
193
+ do { \
194
+ __label__ __gu_failed; \
195
+ \
196
+ __get_user_nocheck(x, ptr, __gu_failed); \
197
+ err = 0; \
198
+ break; \
199
+ __gu_failed: \
200
+ x = 0; \
201
+ err = -EFAULT; \
202
+ } while (0)
203
+
144
204
/**
145
205
* __get_user: - Get a simple variable from user space, with less checking.
146
206
* @x: Variable to store result.
@@ -165,13 +225,16 @@ do { \
165
225
({ \
166
226
const __typeof__(*(ptr)) __user *__gu_ptr = untagged_addr(ptr); \
167
227
long __gu_err = 0; \
228
+ __typeof__(x) __gu_val; \
168
229
\
169
230
__chk_user_ptr(__gu_ptr); \
170
231
\
171
232
__enable_user_access(); \
172
- __get_user_nocheck(x , __gu_ptr, __gu_err); \
233
+ __get_user_error(__gu_val , __gu_ptr, __gu_err); \
173
234
__disable_user_access(); \
174
235
\
236
+ (x) = __gu_val; \
237
+ \
175
238
__gu_err; \
176
239
})
177
240
@@ -201,61 +264,66 @@ do { \
201
264
((x) = (__force __typeof__(x))0, -EFAULT); \
202
265
})
203
266
204
- #define __put_user_asm (insn , x , ptr , err ) \
267
+ #define __put_user_asm (insn , x , ptr , label ) \
205
268
do { \
206
269
__typeof__(*(ptr)) __x = x; \
207
- __asm__ __volatile__ ( \
270
+ asm goto( \
208
271
"1:\n" \
209
- " " insn " %z2, %1\n" \
210
- "2:\n" \
211
- _ASM_EXTABLE_UACCESS_ERR(1b, 2b, %0) \
212
- : "+r" (err), "=m" (*(ptr)) \
213
- : "rJ" (__x)); \
272
+ " " insn " %z0, %1\n" \
273
+ _ASM_EXTABLE(1b, %l2) \
274
+ : : "rJ" (__x), "m"(*(ptr)) : : label); \
214
275
} while (0)
215
276
216
277
#ifdef CONFIG_64BIT
217
- #define __put_user_8 (x , ptr , err ) \
218
- __put_user_asm("sd", x, ptr, err )
278
+ #define __put_user_8 (x , ptr , label ) \
279
+ __put_user_asm("sd", x, ptr, label )
219
280
#else /* !CONFIG_64BIT */
220
- #define __put_user_8 (x , ptr , err ) \
281
+ #define __put_user_8 (x , ptr , label ) \
221
282
do { \
222
283
u32 __user *__ptr = (u32 __user *)(ptr); \
223
284
u64 __x = (__typeof__((x)-(x)))(x); \
224
- __asm__ __volatile__ ( \
285
+ asm goto( \
225
286
"1:\n" \
226
- " sw %z3 , %1 \n" \
287
+ " sw %z0 , %2 \n" \
227
288
"2:\n" \
228
- " sw %z4, %2\n" \
229
- "3:\n" \
230
- _ASM_EXTABLE_UACCESS_ERR(1b, 3b, %0) \
231
- _ASM_EXTABLE_UACCESS_ERR(2b, 3b, %0) \
232
- : "+r" (err), \
233
- "=m" (__ptr[__LSW]), \
234
- "=m" (__ptr[__MSW]) \
235
- : "rJ" (__x), "rJ" (__x >> 32)); \
289
+ " sw %z1, %3\n" \
290
+ _ASM_EXTABLE(1b, %l4) \
291
+ _ASM_EXTABLE(2b, %l4) \
292
+ : : "rJ" (__x), "rJ" (__x >> 32), \
293
+ "m" (__ptr[__LSW]), \
294
+ "m" (__ptr[__MSW]) : : label); \
236
295
} while (0)
237
296
#endif /* CONFIG_64BIT */
238
297
239
- #define __put_user_nocheck (x , __gu_ptr , __pu_err ) \
298
+ #define __put_user_nocheck (x , __gu_ptr , label ) \
240
299
do { \
241
300
switch (sizeof(*__gu_ptr)) { \
242
301
case 1: \
243
- __put_user_asm("sb", (x), __gu_ptr, __pu_err ); \
302
+ __put_user_asm("sb", (x), __gu_ptr, label ); \
244
303
break; \
245
304
case 2: \
246
- __put_user_asm("sh", (x), __gu_ptr, __pu_err ); \
305
+ __put_user_asm("sh", (x), __gu_ptr, label ); \
247
306
break; \
248
307
case 4: \
249
- __put_user_asm("sw", (x), __gu_ptr, __pu_err ); \
308
+ __put_user_asm("sw", (x), __gu_ptr, label ); \
250
309
break; \
251
310
case 8: \
252
- __put_user_8((x), __gu_ptr, __pu_err); \
311
+ __put_user_8((x), __gu_ptr, label); \
253
312
break; \
254
313
default: \
255
314
BUILD_BUG(); \
256
315
} \
257
316
} while (0)
258
317
318
+ #define __put_user_error (x , ptr , err ) \
319
+ do { \
320
+ __label__ err_label; \
321
+ __put_user_nocheck(x, ptr, err_label); \
322
+ break; \
323
+ err_label: \
324
+ (err) = -EFAULT; \
325
+ } while (0)
326
+
259
327
/**
260
328
* __put_user: - Write a simple value into user space, with less checking.
261
329
* @x: Value to copy to user space.
@@ -286,7 +354,7 @@ do { \
286
354
__chk_user_ptr(__gu_ptr); \
287
355
\
288
356
__enable_user_access(); \
289
- __put_user_nocheck (__val, __gu_ptr, __pu_err); \
357
+ __put_user_error (__val, __gu_ptr, __pu_err); \
290
358
__disable_user_access(); \
291
359
\
292
360
__pu_err; \
@@ -351,21 +419,65 @@ unsigned long __must_check clear_user(void __user *to, unsigned long n)
351
419
}
352
420
353
421
#define __get_kernel_nofault (dst , src , type , err_label ) \
422
+ __get_user_nocheck(*((type *)(dst)), (type *)(src), err_label)
423
+
424
+ #define __put_kernel_nofault (dst , src , type , err_label ) \
425
+ __put_user_nocheck(*((type *)(src)), (type *)(dst), err_label)
426
+
427
+ static __must_check __always_inline bool user_access_begin (const void __user * ptr , size_t len )
428
+ {
429
+ if (unlikely (!access_ok (ptr , len )))
430
+ return 0 ;
431
+ __enable_user_access ();
432
+ return 1 ;
433
+ }
434
+ #define user_access_begin user_access_begin
435
+ #define user_access_end __disable_user_access
436
+
437
+ static inline unsigned long user_access_save (void ) { return 0UL ; }
438
+ static inline void user_access_restore (unsigned long enabled ) { }
439
+
440
+ /*
441
+ * We want the unsafe accessors to always be inlined and use
442
+ * the error labels - thus the macro games.
443
+ */
444
+ #define unsafe_put_user (x , ptr , label ) \
445
+ __put_user_nocheck(x, (ptr), label)
446
+
447
+ #define unsafe_get_user (x , ptr , label ) do { \
448
+ __inttype(*(ptr)) __gu_val; \
449
+ __get_user_nocheck(__gu_val, (ptr), label); \
450
+ (x) = (__force __typeof__(*(ptr)))__gu_val; \
451
+ } while (0)
452
+
453
+ #define unsafe_copy_loop (dst , src , len , type , op , label ) \
454
+ while (len >= sizeof(type)) { \
455
+ op(*(type *)(src), (type __user *)(dst), label); \
456
+ dst += sizeof(type); \
457
+ src += sizeof(type); \
458
+ len -= sizeof(type); \
459
+ }
460
+
461
+ #define unsafe_copy_to_user (_dst , _src , _len , label ) \
354
462
do { \
355
- long __kr_err = 0; \
356
- \
357
- __get_user_nocheck(*((type *)(dst)), (type *)(src), __kr_err); \
358
- if (unlikely(__kr_err)) \
359
- goto err_label; \
463
+ char __user *__ucu_dst = (_dst); \
464
+ const char *__ucu_src = (_src); \
465
+ size_t __ucu_len = (_len); \
466
+ unsafe_copy_loop(__ucu_dst, __ucu_src, __ucu_len, u64, unsafe_put_user, label); \
467
+ unsafe_copy_loop(__ucu_dst, __ucu_src, __ucu_len, u32, unsafe_put_user, label); \
468
+ unsafe_copy_loop(__ucu_dst, __ucu_src, __ucu_len, u16, unsafe_put_user, label); \
469
+ unsafe_copy_loop(__ucu_dst, __ucu_src, __ucu_len, u8, unsafe_put_user, label); \
360
470
} while (0)
361
471
362
- #define __put_kernel_nofault ( dst , src , type , err_label ) \
472
+ #define unsafe_copy_from_user ( _dst , _src , _len , label ) \
363
473
do { \
364
- long __kr_err = 0; \
365
- \
366
- __put_user_nocheck(*((type *)(src)), (type *)(dst), __kr_err); \
367
- if (unlikely(__kr_err)) \
368
- goto err_label; \
474
+ char *__ucu_dst = (_dst); \
475
+ const char __user *__ucu_src = (_src); \
476
+ size_t __ucu_len = (_len); \
477
+ unsafe_copy_loop(__ucu_src, __ucu_dst, __ucu_len, u64, unsafe_get_user, label); \
478
+ unsafe_copy_loop(__ucu_src, __ucu_dst, __ucu_len, u32, unsafe_get_user, label); \
479
+ unsafe_copy_loop(__ucu_src, __ucu_dst, __ucu_len, u16, unsafe_get_user, label); \
480
+ unsafe_copy_loop(__ucu_src, __ucu_dst, __ucu_len, u8, unsafe_get_user, label); \
369
481
} while (0)
370
482
371
483
#else /* CONFIG_MMU */
0 commit comments