Commit | Line | Data |
---|---|---|
b2441318 | 1 | /* SPDX-License-Identifier: GPL-2.0 */ |
eed417dd AB |
2 | #ifndef __ASM_GENERIC_UACCESS_H |
3 | #define __ASM_GENERIC_UACCESS_H | |
4 | ||
5 | /* | |
6 | * User space memory access functions, these should work | |
0a4a6647 | 7 | * on any machine that has kernel and user data in the same |
eed417dd AB |
8 | * address space, e.g. all NOMMU machines. |
9 | */ | |
eed417dd AB |
10 | #include <linux/string.h> |
11 | ||
bd79f947 | 12 | #ifdef CONFIG_UACCESS_MEMCPY |
931de11f CH |
13 | #include <asm/unaligned.h> |
14 | ||
0bcd0a2b CH |
15 | static __always_inline int |
16 | __get_user_fn(size_t size, const void __user *from, void *to) | |
bd79f947 | 17 | { |
931de11f CH |
18 | BUILD_BUG_ON(!__builtin_constant_p(size)); |
19 | ||
20 | switch (size) { | |
21 | case 1: | |
d40d8179 | 22 | *(u8 *)to = *((u8 __force *)from); |
931de11f CH |
23 | return 0; |
24 | case 2: | |
25 | *(u16 *)to = get_unaligned((u16 __force *)from); | |
26 | return 0; | |
27 | case 4: | |
28 | *(u32 *)to = get_unaligned((u32 __force *)from); | |
29 | return 0; | |
30 | case 8: | |
31 | *(u64 *)to = get_unaligned((u64 __force *)from); | |
32 | return 0; | |
33 | default: | |
34 | BUILD_BUG(); | |
35 | return 0; | |
36 | } | |
37 | ||
38 | } | |
39 | #define __get_user_fn(sz, u, k) __get_user_fn(sz, u, k) | |
40 | ||
0bcd0a2b CH |
41 | static __always_inline int |
42 | __put_user_fn(size_t size, void __user *to, void *from) | |
931de11f CH |
43 | { |
44 | BUILD_BUG_ON(!__builtin_constant_p(size)); | |
45 | ||
46 | switch (size) { | |
47 | case 1: | |
d40d8179 | 48 | *(u8 __force *)to = *(u8 *)from; |
931de11f CH |
49 | return 0; |
50 | case 2: | |
51 | put_unaligned(*(u16 *)from, (u16 __force *)to); | |
52 | return 0; | |
53 | case 4: | |
54 | put_unaligned(*(u32 *)from, (u32 __force *)to); | |
55 | return 0; | |
56 | case 8: | |
57 | put_unaligned(*(u64 *)from, (u64 __force *)to); | |
58 | return 0; | |
59 | default: | |
60 | BUILD_BUG(); | |
61 | return 0; | |
bd79f947 | 62 | } |
931de11f CH |
63 | } |
64 | #define __put_user_fn(sz, u, k) __put_user_fn(sz, u, k) | |
bd79f947 | 65 | |
2d2d2554 CH |
66 | #define __get_kernel_nofault(dst, src, type, err_label) \ |
67 | do { \ | |
68 | *((type *)dst) = get_unaligned((type *)(src)); \ | |
69 | if (0) /* make sure the label looks used to the compiler */ \ | |
70 | goto err_label; \ | |
71 | } while (0) | |
72 | ||
73 | #define __put_kernel_nofault(dst, src, type, err_label) \ | |
74 | do { \ | |
75 | put_unaligned(*((type *)src), (type *)(dst)); \ | |
76 | if (0) /* make sure the label looks used to the compiler */ \ | |
77 | goto err_label; \ | |
78 | } while (0) | |
79 | ||
80 | #define HAVE_GET_KERNEL_NOFAULT 1 | |
81 | ||
931de11f CH |
82 | static inline __must_check unsigned long |
83 | raw_copy_from_user(void *to, const void __user * from, unsigned long n) | |
84 | { | |
bd79f947 CH |
85 | memcpy(to, (const void __force *)from, n); |
86 | return 0; | |
87 | } | |
88 | ||
89 | static inline __must_check unsigned long | |
90 | raw_copy_to_user(void __user *to, const void *from, unsigned long n) | |
91 | { | |
bd79f947 CH |
92 | memcpy((void __force *)to, from, n); |
93 | return 0; | |
94 | } | |
95 | #define INLINE_COPY_FROM_USER | |
96 | #define INLINE_COPY_TO_USER | |
97 | #endif /* CONFIG_UACCESS_MEMCPY */ | |
98 | ||
3c57fa13 | 99 | #ifdef CONFIG_SET_FS |
eed417dd AB |
100 | #define MAKE_MM_SEG(s) ((mm_segment_t) { (s) }) |
101 | ||
102 | #ifndef KERNEL_DS | |
103 | #define KERNEL_DS MAKE_MM_SEG(~0UL) | |
104 | #endif | |
105 | ||
106 | #ifndef USER_DS | |
107 | #define USER_DS MAKE_MM_SEG(TASK_SIZE - 1) | |
108 | #endif | |
109 | ||
110 | #ifndef get_fs | |
eed417dd AB |
111 | #define get_fs() (current_thread_info()->addr_limit) |
112 | ||
113 | static inline void set_fs(mm_segment_t fs) | |
114 | { | |
115 | current_thread_info()->addr_limit = fs; | |
116 | } | |
117 | #endif | |
118 | ||
428e2976 CH |
119 | #ifndef uaccess_kernel |
120 | #define uaccess_kernel() (get_fs().seg == KERNEL_DS.seg) | |
10a6007b | 121 | #endif |
3c57fa13 | 122 | #endif /* CONFIG_SET_FS */ |
eed417dd | 123 | |
96d4f267 | 124 | #define access_ok(addr, size) __access_ok((unsigned long)(addr),(size)) |
eed417dd AB |
125 | |
126 | /* | |
127 | * The architecture should really override this if possible, at least | |
128 | * doing a check on the get_fs() | |
129 | */ | |
130 | #ifndef __access_ok | |
131 | static inline int __access_ok(unsigned long addr, unsigned long size) | |
132 | { | |
133 | return 1; | |
134 | } | |
135 | #endif | |
136 | ||
eed417dd AB |
137 | /* |
138 | * These are the main single-value transfer routines. They automatically | |
139 | * use the right size if we just have the right pointer type. | |
140 | * This version just falls back to copy_{from,to}_user, which should | |
141 | * provide a fast-path for small values. | |
142 | */ | |
143 | #define __put_user(x, ptr) \ | |
144 | ({ \ | |
145 | __typeof__(*(ptr)) __x = (x); \ | |
146 | int __pu_err = -EFAULT; \ | |
147 | __chk_user_ptr(ptr); \ | |
148 | switch (sizeof (*(ptr))) { \ | |
149 | case 1: \ | |
150 | case 2: \ | |
151 | case 4: \ | |
152 | case 8: \ | |
153 | __pu_err = __put_user_fn(sizeof (*(ptr)), \ | |
154 | ptr, &__x); \ | |
155 | break; \ | |
156 | default: \ | |
157 | __put_user_bad(); \ | |
158 | break; \ | |
159 | } \ | |
160 | __pu_err; \ | |
161 | }) | |
162 | ||
163 | #define put_user(x, ptr) \ | |
164 | ({ \ | |
1985296a | 165 | void __user *__p = (ptr); \ |
e0acd0bd | 166 | might_fault(); \ |
96d4f267 | 167 | access_ok(__p, sizeof(*ptr)) ? \ |
1985296a | 168 | __put_user((x), ((__typeof__(*(ptr)) __user *)__p)) : \ |
eed417dd AB |
169 | -EFAULT; \ |
170 | }) | |
171 | ||
05d88a49 VG |
172 | #ifndef __put_user_fn |
173 | ||
eed417dd AB |
174 | static inline int __put_user_fn(size_t size, void __user *ptr, void *x) |
175 | { | |
d597580d | 176 | return unlikely(raw_copy_to_user(ptr, x, size)) ? -EFAULT : 0; |
eed417dd AB |
177 | } |
178 | ||
05d88a49 VG |
179 | #define __put_user_fn(sz, u, k) __put_user_fn(sz, u, k) |
180 | ||
181 | #endif | |
182 | ||
eed417dd AB |
183 | extern int __put_user_bad(void) __attribute__((noreturn)); |
184 | ||
185 | #define __get_user(x, ptr) \ | |
186 | ({ \ | |
187 | int __gu_err = -EFAULT; \ | |
188 | __chk_user_ptr(ptr); \ | |
189 | switch (sizeof(*(ptr))) { \ | |
190 | case 1: { \ | |
c1aad8dc | 191 | unsigned char __x = 0; \ |
eed417dd AB |
192 | __gu_err = __get_user_fn(sizeof (*(ptr)), \ |
193 | ptr, &__x); \ | |
194 | (x) = *(__force __typeof__(*(ptr)) *) &__x; \ | |
195 | break; \ | |
196 | }; \ | |
197 | case 2: { \ | |
c1aad8dc | 198 | unsigned short __x = 0; \ |
eed417dd AB |
199 | __gu_err = __get_user_fn(sizeof (*(ptr)), \ |
200 | ptr, &__x); \ | |
201 | (x) = *(__force __typeof__(*(ptr)) *) &__x; \ | |
202 | break; \ | |
203 | }; \ | |
204 | case 4: { \ | |
c1aad8dc | 205 | unsigned int __x = 0; \ |
eed417dd AB |
206 | __gu_err = __get_user_fn(sizeof (*(ptr)), \ |
207 | ptr, &__x); \ | |
208 | (x) = *(__force __typeof__(*(ptr)) *) &__x; \ | |
209 | break; \ | |
210 | }; \ | |
211 | case 8: { \ | |
c1aad8dc | 212 | unsigned long long __x = 0; \ |
eed417dd AB |
213 | __gu_err = __get_user_fn(sizeof (*(ptr)), \ |
214 | ptr, &__x); \ | |
215 | (x) = *(__force __typeof__(*(ptr)) *) &__x; \ | |
216 | break; \ | |
217 | }; \ | |
218 | default: \ | |
219 | __get_user_bad(); \ | |
220 | break; \ | |
221 | } \ | |
222 | __gu_err; \ | |
223 | }) | |
224 | ||
225 | #define get_user(x, ptr) \ | |
226 | ({ \ | |
1985296a | 227 | const void __user *__p = (ptr); \ |
e0acd0bd | 228 | might_fault(); \ |
96d4f267 | 229 | access_ok(__p, sizeof(*ptr)) ? \ |
1985296a | 230 | __get_user((x), (__typeof__(*(ptr)) __user *)__p) :\ |
9ad18b75 | 231 | ((x) = (__typeof__(*(ptr)))0,-EFAULT); \ |
eed417dd AB |
232 | }) |
233 | ||
05d88a49 | 234 | #ifndef __get_user_fn |
eed417dd AB |
235 | static inline int __get_user_fn(size_t size, const void __user *ptr, void *x) |
236 | { | |
d597580d | 237 | return unlikely(raw_copy_from_user(x, ptr, size)) ? -EFAULT : 0; |
eed417dd AB |
238 | } |
239 | ||
05d88a49 VG |
240 | #define __get_user_fn(sz, u, k) __get_user_fn(sz, u, k) |
241 | ||
242 | #endif | |
243 | ||
eed417dd AB |
244 | extern int __get_user_bad(void) __attribute__((noreturn)); |
245 | ||
eed417dd AB |
246 | /* |
247 | * Copy a null terminated string from userspace. | |
248 | */ | |
f27180dd | 249 | #ifndef strncpy_from_user |
eed417dd | 250 | static inline long |
f27180dd | 251 | strncpy_from_user(char *dst, const char __user *src, long count) |
eed417dd AB |
252 | { |
253 | char *tmp; | |
f27180dd AB |
254 | |
255 | if (!access_ok(src, 1)) | |
256 | return -EFAULT; | |
257 | ||
eed417dd AB |
258 | strncpy(dst, (const char __force *)src, count); |
259 | for (tmp = dst; *tmp && count > 0; tmp++, count--) | |
260 | ; | |
261 | return (tmp - dst); | |
262 | } | |
263 | #endif | |
264 | ||
f27180dd | 265 | #ifndef strnlen_user |
eed417dd AB |
266 | /* |
267 | * Return the size of a string (including the ending 0) | |
268 | * | |
269 | * Return 0 on exception, a value greater than N if too long | |
f27180dd | 270 | * |
830f5800 MS |
271 | * Unlike strnlen, strnlen_user includes the nul terminator in |
272 | * its returned count. Callers should check for a returned value | |
273 | * greater than N as an indication the string is too long. | |
274 | */ | |
eed417dd AB |
275 | static inline long strnlen_user(const char __user *src, long n) |
276 | { | |
96d4f267 | 277 | if (!access_ok(src, 1)) |
9844813f | 278 | return 0; |
f27180dd AB |
279 | |
280 | return strnlen(src, n) + 1; | |
eed417dd | 281 | } |
f27180dd | 282 | #endif |
eed417dd | 283 | |
eed417dd AB |
284 | /* |
285 | * Zero Userspace | |
286 | */ | |
287 | #ifndef __clear_user | |
288 | static inline __must_check unsigned long | |
289 | __clear_user(void __user *to, unsigned long n) | |
290 | { | |
291 | memset((void __force *)to, 0, n); | |
292 | return 0; | |
293 | } | |
294 | #endif | |
295 | ||
296 | static inline __must_check unsigned long | |
297 | clear_user(void __user *to, unsigned long n) | |
298 | { | |
e0acd0bd | 299 | might_fault(); |
96d4f267 | 300 | if (!access_ok(to, n)) |
eed417dd AB |
301 | return n; |
302 | ||
303 | return __clear_user(to, n); | |
304 | } | |
305 | ||
aaa2e7ac AV |
306 | #include <asm/extable.h> |
307 | ||
eed417dd | 308 | #endif /* __ASM_GENERIC_UACCESS_H */ |