• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* SPDX-License-Identifier: GPL-2.0 */
2 #ifndef __METAG_UACCESS_H
3 #define __METAG_UACCESS_H
4 
5 /*
6  * User space memory access functions
7  */
8 
9 /*
10  * The fs value determines whether argument validity checking should be
11  * performed or not.  If get_fs() == USER_DS, checking is performed, with
12  * get_fs() == KERNEL_DS, checking is bypassed.
13  *
14  * For historical reasons, these macros are grossly misnamed.
15  */
16 
17 #define MAKE_MM_SEG(s)  ((mm_segment_t) { (s) })
18 
19 #define KERNEL_DS       MAKE_MM_SEG(0xFFFFFFFF)
20 #define USER_DS		MAKE_MM_SEG(PAGE_OFFSET)
21 
22 #define get_ds()	(KERNEL_DS)
23 #define get_fs()        (current_thread_info()->addr_limit)
24 #define set_fs(x)       (current_thread_info()->addr_limit = (x))
25 
26 #define segment_eq(a, b)	((a).seg == (b).seg)
27 
__access_ok(unsigned long addr,unsigned long size)28 static inline int __access_ok(unsigned long addr, unsigned long size)
29 {
30 	/*
31 	 * Allow access to the user mapped memory area, but not the system area
32 	 * before it. The check extends to the top of the address space when
33 	 * kernel access is allowed (there's no real reason to user copy to the
34 	 * system area in any case).
35 	 */
36 	if (likely(addr >= META_MEMORY_BASE && addr < get_fs().seg &&
37 		   size <= get_fs().seg - addr))
38 		return true;
39 	/*
40 	 * Explicitly allow NULL pointers here. Parts of the kernel such
41 	 * as readv/writev use access_ok to validate pointers, but want
42 	 * to allow NULL pointers for various reasons. NULL pointers are
43 	 * safe to allow through because the first page is not mappable on
44 	 * Meta.
45 	 */
46 	if (!addr)
47 		return true;
48 	/* Allow access to core code memory area... */
49 	if (addr >= LINCORE_CODE_BASE && addr <= LINCORE_CODE_LIMIT &&
50 	    size <= LINCORE_CODE_LIMIT + 1 - addr)
51 		return true;
52 	/* ... but no other areas. */
53 	return false;
54 }
55 
56 #define access_ok(type, addr, size) __access_ok((unsigned long)(addr),	\
57 						(unsigned long)(size))
58 
59 #include <asm/extable.h>
60 
61 /*
62  * These are the main single-value transfer routines.  They automatically
63  * use the right size if we just have the right pointer type.
64  */
65 
66 #define put_user(x, ptr) \
67 	__put_user_check((__typeof__(*(ptr)))(x), (ptr), sizeof(*(ptr)))
68 #define __put_user(x, ptr) \
69 	__put_user_nocheck((__typeof__(*(ptr)))(x), (ptr), sizeof(*(ptr)))
70 
71 extern void __put_user_bad(void);
72 
73 #define __put_user_nocheck(x, ptr, size)		\
74 ({                                                      \
75 	long __pu_err;                                  \
76 	__put_user_size((x), (ptr), (size), __pu_err);	\
77 	__pu_err;                                       \
78 })
79 
80 #define __put_user_check(x, ptr, size)				\
81 ({                                                              \
82 	long __pu_err = -EFAULT;                                \
83 	__typeof__(*(ptr)) __user *__pu_addr = (ptr);           \
84 	if (access_ok(VERIFY_WRITE, __pu_addr, size))		\
85 		__put_user_size((x), __pu_addr, (size), __pu_err);	\
86 	__pu_err;                                               \
87 })
88 
89 extern long __put_user_asm_b(unsigned int x, void __user *addr);
90 extern long __put_user_asm_w(unsigned int x, void __user *addr);
91 extern long __put_user_asm_d(unsigned int x, void __user *addr);
92 extern long __put_user_asm_l(unsigned long long x, void __user *addr);
93 
94 #define __put_user_size(x, ptr, size, retval)				\
95 do {                                                                    \
96 	retval = 0;                                                     \
97 	switch (size) {                                                 \
98 	case 1:								\
99 		retval = __put_user_asm_b((__force unsigned int)x, ptr);\
100 		break;							\
101 	case 2:								\
102 		retval = __put_user_asm_w((__force unsigned int)x, ptr);\
103 		break;							\
104 	case 4:								\
105 		retval = __put_user_asm_d((__force unsigned int)x, ptr);\
106 		break;							\
107 	case 8:								\
108 		retval = __put_user_asm_l((__force unsigned long long)x,\
109 					  ptr);				\
110 		break;							\
111 	default:							\
112 		__put_user_bad();					\
113 	}								\
114 } while (0)
115 
116 #define get_user(x, ptr) \
117 	__get_user_check((x), (ptr), sizeof(*(ptr)))
118 #define __get_user(x, ptr) \
119 	__get_user_nocheck((x), (ptr), sizeof(*(ptr)))
120 
121 extern long __get_user_bad(void);
122 
123 #define __get_user_nocheck(x, ptr, size)			\
124 ({                                                              \
125 	long __gu_err;						\
126 	long long __gu_val;					\
127 	__get_user_size(__gu_val, (ptr), (size), __gu_err);	\
128 	(x) = (__force __typeof__(*(ptr)))__gu_val;             \
129 	__gu_err;                                               \
130 })
131 
132 #define __get_user_check(x, ptr, size)					\
133 ({                                                                      \
134 	long __gu_err = -EFAULT;					\
135 	long long __gu_val = 0;						\
136 	const __typeof__(*(ptr)) __user *__gu_addr = (ptr);		\
137 	if (access_ok(VERIFY_READ, __gu_addr, size))			\
138 		__get_user_size(__gu_val, __gu_addr, (size), __gu_err);	\
139 	(x) = (__force __typeof__(*(ptr)))__gu_val;                     \
140 	__gu_err;                                                       \
141 })
142 
143 extern unsigned char __get_user_asm_b(const void __user *addr, long *err);
144 extern unsigned short __get_user_asm_w(const void __user *addr, long *err);
145 extern unsigned int __get_user_asm_d(const void __user *addr, long *err);
146 extern unsigned long long __get_user_asm_l(const void __user *addr, long *err);
147 
148 #define __get_user_size(x, ptr, size, retval)			\
149 do {                                                            \
150 	retval = 0;                                             \
151 	switch (size) {                                         \
152 	case 1:							\
153 		x = __get_user_asm_b(ptr, &retval); break;	\
154 	case 2:							\
155 		x = __get_user_asm_w(ptr, &retval); break;	\
156 	case 4:							\
157 		x = __get_user_asm_d(ptr, &retval); break;	\
158 	case 8:							\
159 		x = __get_user_asm_l(ptr, &retval); break;	\
160 	default:						\
161 		(x) = __get_user_bad();				\
162 	}                                                       \
163 } while (0)
164 
165 /*
166  * Copy a null terminated string from userspace.
167  *
168  * Must return:
169  * -EFAULT		for an exception
170  * count		if we hit the buffer limit
171  * bytes copied		if we hit a null byte
172  * (without the null byte)
173  */
174 
175 extern long __must_check __strncpy_from_user(char *dst, const char __user *src,
176 					     long count);
177 
178 static inline long
strncpy_from_user(char * dst,const char __user * src,long count)179 strncpy_from_user(char *dst, const char __user *src, long count)
180 {
181 	if (!access_ok(VERIFY_READ, src, 1))
182 		return -EFAULT;
183 	return __strncpy_from_user(dst, src, count);
184 }
185 /*
186  * Return the size of a string (including the ending 0)
187  *
188  * Return 0 on exception, a value greater than N if too long
189  */
190 extern long __must_check strnlen_user(const char __user *src, long count);
191 
192 extern unsigned long raw_copy_from_user(void *to, const void __user *from,
193 					unsigned long n);
194 extern unsigned long raw_copy_to_user(void __user *to, const void *from,
195 				      unsigned long n);
196 
197 /*
198  * Zero Userspace
199  */
200 
201 extern unsigned long __must_check __do_clear_user(void __user *to,
202 						  unsigned long n);
203 
clear_user(void __user * to,unsigned long n)204 static inline unsigned long clear_user(void __user *to, unsigned long n)
205 {
206 	if (access_ok(VERIFY_WRITE, to, n))
207 		return __do_clear_user(to, n);
208 	return n;
209 }
210 
211 #define __clear_user(to, n)            __do_clear_user(to, n)
212 
213 #endif /* _METAG_UACCESS_H */
214