Warning: This file is not a C or C++ file. It does not have highlighting.
1 | /* SPDX-License-Identifier: GPL-2.0 */ |
---|---|
2 | #ifndef __ASM_GENERIC_UACCESS_H |
3 | #define __ASM_GENERIC_UACCESS_H |
4 | |
5 | /* |
6 | * User space memory access functions, these should work |
7 | * on any machine that has kernel and user data in the same |
8 | * address space, e.g. all NOMMU machines. |
9 | */ |
10 | #include <linux/string.h> |
11 | #include <asm-generic/access_ok.h> |
12 | |
13 | #ifdef CONFIG_UACCESS_MEMCPY |
14 | #include <asm/unaligned.h> |
15 | |
16 | static __always_inline int |
17 | __get_user_fn(size_t size, const void __user *from, void *to) |
18 | { |
19 | BUILD_BUG_ON(!__builtin_constant_p(size)); |
20 | |
21 | switch (size) { |
22 | case 1: |
23 | *(u8 *)to = *((u8 __force *)from); |
24 | return 0; |
25 | case 2: |
26 | *(u16 *)to = get_unaligned((u16 __force *)from); |
27 | return 0; |
28 | case 4: |
29 | *(u32 *)to = get_unaligned((u32 __force *)from); |
30 | return 0; |
31 | case 8: |
32 | *(u64 *)to = get_unaligned((u64 __force *)from); |
33 | return 0; |
34 | default: |
35 | BUILD_BUG(); |
36 | return 0; |
37 | } |
38 | |
39 | } |
40 | #define __get_user_fn(sz, u, k) __get_user_fn(sz, u, k) |
41 | |
42 | static __always_inline int |
43 | __put_user_fn(size_t size, void __user *to, void *from) |
44 | { |
45 | BUILD_BUG_ON(!__builtin_constant_p(size)); |
46 | |
47 | switch (size) { |
48 | case 1: |
49 | *(u8 __force *)to = *(u8 *)from; |
50 | return 0; |
51 | case 2: |
52 | put_unaligned(*(u16 *)from, (u16 __force *)to); |
53 | return 0; |
54 | case 4: |
55 | put_unaligned(*(u32 *)from, (u32 __force *)to); |
56 | return 0; |
57 | case 8: |
58 | put_unaligned(*(u64 *)from, (u64 __force *)to); |
59 | return 0; |
60 | default: |
61 | BUILD_BUG(); |
62 | return 0; |
63 | } |
64 | } |
65 | #define __put_user_fn(sz, u, k) __put_user_fn(sz, u, k) |
66 | |
67 | #define __get_kernel_nofault(dst, src, type, err_label) \ |
68 | do { \ |
69 | *((type *)dst) = get_unaligned((type *)(src)); \ |
70 | if (0) /* make sure the label looks used to the compiler */ \ |
71 | goto err_label; \ |
72 | } while (0) |
73 | |
74 | #define __put_kernel_nofault(dst, src, type, err_label) \ |
75 | do { \ |
76 | put_unaligned(*((type *)src), (type *)(dst)); \ |
77 | if (0) /* make sure the label looks used to the compiler */ \ |
78 | goto err_label; \ |
79 | } while (0) |
80 | |
81 | static inline __must_check unsigned long |
82 | raw_copy_from_user(void *to, const void __user * from, unsigned long n) |
83 | { |
84 | memcpy(to, (const void __force *)from, n); |
85 | return 0; |
86 | } |
87 | |
88 | static inline __must_check unsigned long |
89 | raw_copy_to_user(void __user *to, const void *from, unsigned long n) |
90 | { |
91 | memcpy((void __force *)to, from, n); |
92 | return 0; |
93 | } |
94 | #define INLINE_COPY_FROM_USER |
95 | #define INLINE_COPY_TO_USER |
96 | #endif /* CONFIG_UACCESS_MEMCPY */ |
97 | |
98 | /* |
99 | * These are the main single-value transfer routines. They automatically |
100 | * use the right size if we just have the right pointer type. |
101 | * This version just falls back to copy_{from,to}_user, which should |
102 | * provide a fast-path for small values. |
103 | */ |
104 | #define __put_user(x, ptr) \ |
105 | ({ \ |
106 | __typeof__(*(ptr)) __x = (x); \ |
107 | int __pu_err = -EFAULT; \ |
108 | __chk_user_ptr(ptr); \ |
109 | switch (sizeof (*(ptr))) { \ |
110 | case 1: \ |
111 | case 2: \ |
112 | case 4: \ |
113 | case 8: \ |
114 | __pu_err = __put_user_fn(sizeof (*(ptr)), \ |
115 | ptr, &__x); \ |
116 | break; \ |
117 | default: \ |
118 | __put_user_bad(); \ |
119 | break; \ |
120 | } \ |
121 | __pu_err; \ |
122 | }) |
123 | |
124 | #define put_user(x, ptr) \ |
125 | ({ \ |
126 | void __user *__p = (ptr); \ |
127 | might_fault(); \ |
128 | access_ok(__p, sizeof(*ptr)) ? \ |
129 | __put_user((x), ((__typeof__(*(ptr)) __user *)__p)) : \ |
130 | -EFAULT; \ |
131 | }) |
132 | |
133 | #ifndef __put_user_fn |
134 | |
135 | static inline int __put_user_fn(size_t size, void __user *ptr, void *x) |
136 | { |
137 | return unlikely(raw_copy_to_user(ptr, x, size)) ? -EFAULT : 0; |
138 | } |
139 | |
140 | #define __put_user_fn(sz, u, k) __put_user_fn(sz, u, k) |
141 | |
142 | #endif |
143 | |
144 | extern int __put_user_bad(void) __attribute__((noreturn)); |
145 | |
146 | #define __get_user(x, ptr) \ |
147 | ({ \ |
148 | int __gu_err = -EFAULT; \ |
149 | __chk_user_ptr(ptr); \ |
150 | switch (sizeof(*(ptr))) { \ |
151 | case 1: { \ |
152 | unsigned char __x = 0; \ |
153 | __gu_err = __get_user_fn(sizeof (*(ptr)), \ |
154 | ptr, &__x); \ |
155 | (x) = *(__force __typeof__(*(ptr)) *) &__x; \ |
156 | break; \ |
157 | }; \ |
158 | case 2: { \ |
159 | unsigned short __x = 0; \ |
160 | __gu_err = __get_user_fn(sizeof (*(ptr)), \ |
161 | ptr, &__x); \ |
162 | (x) = *(__force __typeof__(*(ptr)) *) &__x; \ |
163 | break; \ |
164 | }; \ |
165 | case 4: { \ |
166 | unsigned int __x = 0; \ |
167 | __gu_err = __get_user_fn(sizeof (*(ptr)), \ |
168 | ptr, &__x); \ |
169 | (x) = *(__force __typeof__(*(ptr)) *) &__x; \ |
170 | break; \ |
171 | }; \ |
172 | case 8: { \ |
173 | unsigned long long __x = 0; \ |
174 | __gu_err = __get_user_fn(sizeof (*(ptr)), \ |
175 | ptr, &__x); \ |
176 | (x) = *(__force __typeof__(*(ptr)) *) &__x; \ |
177 | break; \ |
178 | }; \ |
179 | default: \ |
180 | __get_user_bad(); \ |
181 | break; \ |
182 | } \ |
183 | __gu_err; \ |
184 | }) |
185 | |
186 | #define get_user(x, ptr) \ |
187 | ({ \ |
188 | const void __user *__p = (ptr); \ |
189 | might_fault(); \ |
190 | access_ok(__p, sizeof(*ptr)) ? \ |
191 | __get_user((x), (__typeof__(*(ptr)) __user *)__p) :\ |
192 | ((x) = (__typeof__(*(ptr)))0,-EFAULT); \ |
193 | }) |
194 | |
195 | #ifndef __get_user_fn |
196 | static inline int __get_user_fn(size_t size, const void __user *ptr, void *x) |
197 | { |
198 | return unlikely(raw_copy_from_user(x, ptr, size)) ? -EFAULT : 0; |
199 | } |
200 | |
201 | #define __get_user_fn(sz, u, k) __get_user_fn(sz, u, k) |
202 | |
203 | #endif |
204 | |
205 | extern int __get_user_bad(void) __attribute__((noreturn)); |
206 | |
207 | /* |
208 | * Zero Userspace |
209 | */ |
210 | #ifndef __clear_user |
211 | static inline __must_check unsigned long |
212 | __clear_user(void __user *to, unsigned long n) |
213 | { |
214 | memset((void __force *)to, 0, n); |
215 | return 0; |
216 | } |
217 | #endif |
218 | |
219 | static inline __must_check unsigned long |
220 | clear_user(void __user *to, unsigned long n) |
221 | { |
222 | might_fault(); |
223 | if (!access_ok(to, n)) |
224 | return n; |
225 | |
226 | return __clear_user(to, n); |
227 | } |
228 | |
229 | #include <asm/extable.h> |
230 | |
231 | __must_check long strncpy_from_user(char *dst, const char __user *src, |
232 | long count); |
233 | __must_check long strnlen_user(const char __user *src, long n); |
234 | |
235 | #endif /* __ASM_GENERIC_UACCESS_H */ |
236 |
Warning: This file is not a C or C++ file. It does not have highlighting.