xref: /openbmc/linux/include/asm-generic/uaccess.h (revision df687341)
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 
12 #include <asm/segment.h>
13 
14 #define MAKE_MM_SEG(s)	((mm_segment_t) { (s) })
15 
16 #ifndef KERNEL_DS
17 #define KERNEL_DS	MAKE_MM_SEG(~0UL)
18 #endif
19 
20 #ifndef USER_DS
21 #define USER_DS		MAKE_MM_SEG(TASK_SIZE - 1)
22 #endif
23 
24 #ifndef get_fs
25 #define get_ds()	(KERNEL_DS)
26 #define get_fs()	(current_thread_info()->addr_limit)
27 
28 static inline void set_fs(mm_segment_t fs)
29 {
30 	current_thread_info()->addr_limit = fs;
31 }
32 #endif
33 
34 #ifndef segment_eq
35 #define segment_eq(a, b) ((a).seg == (b).seg)
36 #endif
37 
38 #define access_ok(addr, size) __access_ok((unsigned long)(addr),(size))
39 
40 /*
41  * The architecture should really override this if possible, at least
42  * doing a check on the get_fs()
43  */
44 #ifndef __access_ok
45 static inline int __access_ok(unsigned long addr, unsigned long size)
46 {
47 	return 1;
48 }
49 #endif
50 
51 /*
52  * These are the main single-value transfer routines.  They automatically
53  * use the right size if we just have the right pointer type.
54  * This version just falls back to copy_{from,to}_user, which should
55  * provide a fast-path for small values.
56  */
57 #define __put_user(x, ptr) \
58 ({								\
59 	__typeof__(*(ptr)) __x = (x);				\
60 	int __pu_err = -EFAULT;					\
61         __chk_user_ptr(ptr);                                    \
62 	switch (sizeof (*(ptr))) {				\
63 	case 1:							\
64 	case 2:							\
65 	case 4:							\
66 	case 8:							\
67 		__pu_err = __put_user_fn(sizeof (*(ptr)),	\
68 					 ptr, &__x);		\
69 		break;						\
70 	default:						\
71 		__put_user_bad();				\
72 		break;						\
73 	 }							\
74 	__pu_err;						\
75 })
76 
77 #define put_user(x, ptr)					\
78 ({								\
79 	void __user *__p = (ptr);				\
80 	might_fault();						\
81 	access_ok(__p, sizeof(*ptr)) ?		\
82 		__put_user((x), ((__typeof__(*(ptr)) __user *)__p)) :	\
83 		-EFAULT;					\
84 })
85 
86 #ifndef __put_user_fn
87 
88 static inline int __put_user_fn(size_t size, void __user *ptr, void *x)
89 {
90 	return unlikely(raw_copy_to_user(ptr, x, size)) ? -EFAULT : 0;
91 }
92 
93 #define __put_user_fn(sz, u, k)	__put_user_fn(sz, u, k)
94 
95 #endif
96 
97 extern int __put_user_bad(void) __attribute__((noreturn));
98 
99 #define __get_user(x, ptr)					\
100 ({								\
101 	int __gu_err = -EFAULT;					\
102 	__chk_user_ptr(ptr);					\
103 	switch (sizeof(*(ptr))) {				\
104 	case 1: {						\
105 		unsigned char __x = 0;				\
106 		__gu_err = __get_user_fn(sizeof (*(ptr)),	\
107 					 ptr, &__x);		\
108 		(x) = *(__force __typeof__(*(ptr)) *) &__x;	\
109 		break;						\
110 	};							\
111 	case 2: {						\
112 		unsigned short __x = 0;				\
113 		__gu_err = __get_user_fn(sizeof (*(ptr)),	\
114 					 ptr, &__x);		\
115 		(x) = *(__force __typeof__(*(ptr)) *) &__x;	\
116 		break;						\
117 	};							\
118 	case 4: {						\
119 		unsigned int __x = 0;				\
120 		__gu_err = __get_user_fn(sizeof (*(ptr)),	\
121 					 ptr, &__x);		\
122 		(x) = *(__force __typeof__(*(ptr)) *) &__x;	\
123 		break;						\
124 	};							\
125 	case 8: {						\
126 		unsigned long long __x = 0;			\
127 		__gu_err = __get_user_fn(sizeof (*(ptr)),	\
128 					 ptr, &__x);		\
129 		(x) = *(__force __typeof__(*(ptr)) *) &__x;	\
130 		break;						\
131 	};							\
132 	default:						\
133 		__get_user_bad();				\
134 		break;						\
135 	}							\
136 	__gu_err;						\
137 })
138 
139 #define get_user(x, ptr)					\
140 ({								\
141 	const void __user *__p = (ptr);				\
142 	might_fault();						\
143 	access_ok(__p, sizeof(*ptr)) ?		\
144 		__get_user((x), (__typeof__(*(ptr)) __user *)__p) :\
145 		((x) = (__typeof__(*(ptr)))0,-EFAULT);		\
146 })
147 
148 #ifndef __get_user_fn
149 static inline int __get_user_fn(size_t size, const void __user *ptr, void *x)
150 {
151 	return unlikely(raw_copy_from_user(x, ptr, size)) ? -EFAULT : 0;
152 }
153 
154 #define __get_user_fn(sz, u, k)	__get_user_fn(sz, u, k)
155 
156 #endif
157 
158 extern int __get_user_bad(void) __attribute__((noreturn));
159 
160 /*
161  * Copy a null terminated string from userspace.
162  */
163 #ifndef __strncpy_from_user
164 static inline long
165 __strncpy_from_user(char *dst, const char __user *src, long count)
166 {
167 	char *tmp;
168 	strncpy(dst, (const char __force *)src, count);
169 	for (tmp = dst; *tmp && count > 0; tmp++, count--)
170 		;
171 	return (tmp - dst);
172 }
173 #endif
174 
175 static inline long
176 strncpy_from_user(char *dst, const char __user *src, long count)
177 {
178 	if (!access_ok(src, 1))
179 		return -EFAULT;
180 	return __strncpy_from_user(dst, src, count);
181 }
182 
183 /*
184  * Return the size of a string (including the ending 0)
185  *
186  * Return 0 on exception, a value greater than N if too long
187  */
188 #ifndef __strnlen_user
189 #define __strnlen_user(s, n) (strnlen((s), (n)) + 1)
190 #endif
191 
192 /*
193  * Unlike strnlen, strnlen_user includes the nul terminator in
194  * its returned count. Callers should check for a returned value
195  * greater than N as an indication the string is too long.
196  */
197 static inline long strnlen_user(const char __user *src, long n)
198 {
199 	if (!access_ok(src, 1))
200 		return 0;
201 	return __strnlen_user(src, n);
202 }
203 
204 /*
205  * Zero Userspace
206  */
207 #ifndef __clear_user
208 static inline __must_check unsigned long
209 __clear_user(void __user *to, unsigned long n)
210 {
211 	memset((void __force *)to, 0, n);
212 	return 0;
213 }
214 #endif
215 
216 static inline __must_check unsigned long
217 clear_user(void __user *to, unsigned long n)
218 {
219 	might_fault();
220 	if (!access_ok(to, n))
221 		return n;
222 
223 	return __clear_user(to, n);
224 }
225 
226 #include <asm/extable.h>
227 
228 #endif /* __ASM_GENERIC_UACCESS_H */
229