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 | ||
931de11f CH |
80 | static inline __must_check unsigned long |
81 | raw_copy_from_user(void *to, const void __user * from, unsigned long n) | |
82 | { | |
bd79f947 CH |
83 | memcpy(to, (const void __force *)from, n); |
84 | return 0; | |
85 | } | |
86 | ||
87 | static inline __must_check unsigned long | |
88 | raw_copy_to_user(void __user *to, const void *from, unsigned long n) | |
89 | { | |
bd79f947 CH |
90 | memcpy((void __force *)to, from, n); |
91 | return 0; | |
92 | } | |
93 | #define INLINE_COPY_FROM_USER | |
94 | #define INLINE_COPY_TO_USER | |
95 | #endif /* CONFIG_UACCESS_MEMCPY */ | |
96 | ||
3c57fa13 | 97 | #ifdef CONFIG_SET_FS |
eed417dd AB |
98 | #define MAKE_MM_SEG(s) ((mm_segment_t) { (s) }) |
99 | ||
100 | #ifndef KERNEL_DS | |
101 | #define KERNEL_DS MAKE_MM_SEG(~0UL) | |
102 | #endif | |
103 | ||
104 | #ifndef USER_DS | |
105 | #define USER_DS MAKE_MM_SEG(TASK_SIZE - 1) | |
106 | #endif | |
107 | ||
108 | #ifndef get_fs | |
eed417dd AB |
109 | #define get_fs() (current_thread_info()->addr_limit) |
110 | ||
111 | static inline void set_fs(mm_segment_t fs) | |
112 | { | |
113 | current_thread_info()->addr_limit = fs; | |
114 | } | |
115 | #endif | |
116 | ||
3c57fa13 | 117 | #endif /* CONFIG_SET_FS */ |
eed417dd | 118 | |
12700c17 | 119 | #include <asm-generic/access_ok.h> |
eed417dd | 120 | |
eed417dd AB |
121 | /* |
122 | * These are the main single-value transfer routines. They automatically | |
123 | * use the right size if we just have the right pointer type. | |
124 | * This version just falls back to copy_{from,to}_user, which should | |
125 | * provide a fast-path for small values. | |
126 | */ | |
127 | #define __put_user(x, ptr) \ | |
128 | ({ \ | |
129 | __typeof__(*(ptr)) __x = (x); \ | |
130 | int __pu_err = -EFAULT; \ | |
131 | __chk_user_ptr(ptr); \ | |
132 | switch (sizeof (*(ptr))) { \ | |
133 | case 1: \ | |
134 | case 2: \ | |
135 | case 4: \ | |
136 | case 8: \ | |
137 | __pu_err = __put_user_fn(sizeof (*(ptr)), \ | |
138 | ptr, &__x); \ | |
139 | break; \ | |
140 | default: \ | |
141 | __put_user_bad(); \ | |
142 | break; \ | |
143 | } \ | |
144 | __pu_err; \ | |
145 | }) | |
146 | ||
147 | #define put_user(x, ptr) \ | |
148 | ({ \ | |
1985296a | 149 | void __user *__p = (ptr); \ |
e0acd0bd | 150 | might_fault(); \ |
96d4f267 | 151 | access_ok(__p, sizeof(*ptr)) ? \ |
1985296a | 152 | __put_user((x), ((__typeof__(*(ptr)) __user *)__p)) : \ |
eed417dd AB |
153 | -EFAULT; \ |
154 | }) | |
155 | ||
05d88a49 VG |
156 | #ifndef __put_user_fn |
157 | ||
eed417dd AB |
158 | static inline int __put_user_fn(size_t size, void __user *ptr, void *x) |
159 | { | |
d597580d | 160 | return unlikely(raw_copy_to_user(ptr, x, size)) ? -EFAULT : 0; |
eed417dd AB |
161 | } |
162 | ||
05d88a49 VG |
163 | #define __put_user_fn(sz, u, k) __put_user_fn(sz, u, k) |
164 | ||
165 | #endif | |
166 | ||
eed417dd AB |
167 | extern int __put_user_bad(void) __attribute__((noreturn)); |
168 | ||
169 | #define __get_user(x, ptr) \ | |
170 | ({ \ | |
171 | int __gu_err = -EFAULT; \ | |
172 | __chk_user_ptr(ptr); \ | |
173 | switch (sizeof(*(ptr))) { \ | |
174 | case 1: { \ | |
c1aad8dc | 175 | unsigned char __x = 0; \ |
eed417dd AB |
176 | __gu_err = __get_user_fn(sizeof (*(ptr)), \ |
177 | ptr, &__x); \ | |
178 | (x) = *(__force __typeof__(*(ptr)) *) &__x; \ | |
179 | break; \ | |
180 | }; \ | |
181 | case 2: { \ | |
c1aad8dc | 182 | unsigned short __x = 0; \ |
eed417dd AB |
183 | __gu_err = __get_user_fn(sizeof (*(ptr)), \ |
184 | ptr, &__x); \ | |
185 | (x) = *(__force __typeof__(*(ptr)) *) &__x; \ | |
186 | break; \ | |
187 | }; \ | |
188 | case 4: { \ | |
c1aad8dc | 189 | unsigned int __x = 0; \ |
eed417dd AB |
190 | __gu_err = __get_user_fn(sizeof (*(ptr)), \ |
191 | ptr, &__x); \ | |
192 | (x) = *(__force __typeof__(*(ptr)) *) &__x; \ | |
193 | break; \ | |
194 | }; \ | |
195 | case 8: { \ | |
c1aad8dc | 196 | unsigned long long __x = 0; \ |
eed417dd AB |
197 | __gu_err = __get_user_fn(sizeof (*(ptr)), \ |
198 | ptr, &__x); \ | |
199 | (x) = *(__force __typeof__(*(ptr)) *) &__x; \ | |
200 | break; \ | |
201 | }; \ | |
202 | default: \ | |
203 | __get_user_bad(); \ | |
204 | break; \ | |
205 | } \ | |
206 | __gu_err; \ | |
207 | }) | |
208 | ||
209 | #define get_user(x, ptr) \ | |
210 | ({ \ | |
1985296a | 211 | const void __user *__p = (ptr); \ |
e0acd0bd | 212 | might_fault(); \ |
96d4f267 | 213 | access_ok(__p, sizeof(*ptr)) ? \ |
1985296a | 214 | __get_user((x), (__typeof__(*(ptr)) __user *)__p) :\ |
9ad18b75 | 215 | ((x) = (__typeof__(*(ptr)))0,-EFAULT); \ |
eed417dd AB |
216 | }) |
217 | ||
05d88a49 | 218 | #ifndef __get_user_fn |
eed417dd AB |
219 | static inline int __get_user_fn(size_t size, const void __user *ptr, void *x) |
220 | { | |
d597580d | 221 | return unlikely(raw_copy_from_user(x, ptr, size)) ? -EFAULT : 0; |
eed417dd AB |
222 | } |
223 | ||
05d88a49 VG |
224 | #define __get_user_fn(sz, u, k) __get_user_fn(sz, u, k) |
225 | ||
226 | #endif | |
227 | ||
eed417dd AB |
228 | extern int __get_user_bad(void) __attribute__((noreturn)); |
229 | ||
eed417dd AB |
230 | /* |
231 | * Zero Userspace | |
232 | */ | |
233 | #ifndef __clear_user | |
234 | static inline __must_check unsigned long | |
235 | __clear_user(void __user *to, unsigned long n) | |
236 | { | |
237 | memset((void __force *)to, 0, n); | |
238 | return 0; | |
239 | } | |
240 | #endif | |
241 | ||
242 | static inline __must_check unsigned long | |
243 | clear_user(void __user *to, unsigned long n) | |
244 | { | |
e0acd0bd | 245 | might_fault(); |
96d4f267 | 246 | if (!access_ok(to, n)) |
eed417dd AB |
247 | return n; |
248 | ||
249 | return __clear_user(to, n); | |
250 | } | |
251 | ||
aaa2e7ac AV |
252 | #include <asm/extable.h> |
253 | ||
98b861a3 AB |
254 | __must_check long strncpy_from_user(char *dst, const char __user *src, |
255 | long count); | |
256 | __must_check long strnlen_user(const char __user *src, long n); | |
257 | ||
eed417dd | 258 | #endif /* __ASM_GENERIC_UACCESS_H */ |