uaccess: generalize access_ok()
[linux-2.6-block.git] / include / asm-generic / uaccess.h
CommitLineData
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
15static __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
41static __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) \
67do { \
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) \
74do { \
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
80static inline __must_check unsigned long
81raw_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
87static inline __must_check unsigned long
88raw_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
111static 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
158static 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
167extern 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
219static 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
228extern int __get_user_bad(void) __attribute__((noreturn));
229
eed417dd
AB
230/*
231 * Zero Userspace
232 */
233#ifndef __clear_user
234static 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
242static inline __must_check unsigned long
243clear_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 */