• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Access kernel memory without faulting.
3  */
4 #include <linux/export.h>
5 #include <linux/mm.h>
6 #include <linux/uaccess.h>
7 
8 static __always_inline long
probe_read_common(void * dst,const void __user * src,size_t size)9 probe_read_common(void *dst, const void __user *src, size_t size)
10 {
11 	long ret;
12 
13 	pagefault_disable();
14 	ret = __copy_from_user_inatomic(dst, src, size);
15 	pagefault_enable();
16 
17 	return ret ? -EFAULT : 0;
18 }
19 
20 static __always_inline long
probe_write_common(void __user * dst,const void * src,size_t size)21 probe_write_common(void __user *dst, const void *src, size_t size)
22 {
23 	long ret;
24 
25 	pagefault_disable();
26 	ret = __copy_to_user_inatomic(dst, src, size);
27 	pagefault_enable();
28 
29 	return ret ? -EFAULT : 0;
30 }
31 
32 /**
33  * probe_kernel_read(): safely attempt to read from a kernel-space location
34  * @dst: pointer to the buffer that shall take the data
35  * @src: address to read from
36  * @size: size of the data chunk
37  *
38  * Safely read from address @src to the buffer at @dst.  If a kernel fault
39  * happens, handle that and return -EFAULT.
40  *
41  * We ensure that the copy_from_user is executed in atomic context so that
42  * do_page_fault() doesn't attempt to take mmap_sem.  This makes
43  * probe_kernel_read() suitable for use within regions where the caller
44  * already holds mmap_sem, or other locks which nest inside mmap_sem.
45  */
46 
47 long __weak probe_kernel_read(void *dst, const void *src, size_t size)
48     __attribute__((alias("__probe_kernel_read")));
49 
__probe_kernel_read(void * dst,const void * src,size_t size)50 long __probe_kernel_read(void *dst, const void *src, size_t size)
51 {
52 	long ret;
53 	mm_segment_t old_fs = get_fs();
54 
55 	set_fs(KERNEL_DS);
56 	ret = probe_read_common(dst, (__force const void __user *)src, size);
57 	set_fs(old_fs);
58 
59 	return ret;
60 }
61 EXPORT_SYMBOL_GPL(probe_kernel_read);
62 
63 /**
64  * probe_user_read(): safely attempt to read from a user-space location
65  * @dst: pointer to the buffer that shall take the data
66  * @src: address to read from. This must be a user address.
67  * @size: size of the data chunk
68  *
69  * Safely read from user address @src to the buffer at @dst. If a kernel fault
70  * happens, handle that and return -EFAULT.
71  */
72 
73 long __weak probe_user_read(void *dst, const void __user *src, size_t size)
74     __attribute__((alias("__probe_user_read")));
75 
__probe_user_read(void * dst,const void __user * src,size_t size)76 long __probe_user_read(void *dst, const void __user *src, size_t size)
77 {
78 	long ret = -EFAULT;
79 	mm_segment_t old_fs = get_fs();
80 
81 	set_fs(USER_DS);
82 	if (access_ok(VERIFY_READ, src, size))
83 		ret = probe_read_common(dst, src, size);
84 	set_fs(old_fs);
85 
86 	return ret;
87 }
88 EXPORT_SYMBOL_GPL(probe_user_read);
89 
90 /**
91  * probe_kernel_write(): safely attempt to write to a location
92  * @dst: address to write to
93  * @src: pointer to the data that shall be written
94  * @size: size of the data chunk
95  *
96  * Safely write to address @dst from the buffer at @src.  If a kernel fault
97  * happens, handle that and return -EFAULT.
98  */
99 
100 long __weak probe_kernel_write(void *dst, const void *src, size_t size)
101     __attribute__((alias("__probe_kernel_write")));
102 
__probe_kernel_write(void * dst,const void * src,size_t size)103 long __probe_kernel_write(void *dst, const void *src, size_t size)
104 {
105 	long ret;
106 	mm_segment_t old_fs = get_fs();
107 
108 	set_fs(KERNEL_DS);
109 	ret = probe_write_common((__force void __user *)dst, src, size);
110 	set_fs(old_fs);
111 
112 	return ret;
113 }
114 EXPORT_SYMBOL_GPL(probe_kernel_write);
115 
116 /**
117  * probe_user_write(): safely attempt to write to a user-space location
118  * @dst: address to write to
119  * @src: pointer to the data that shall be written
120  * @size: size of the data chunk
121  *
122  * Safely write to address @dst from the buffer at @src.  If a kernel fault
123  * happens, handle that and return -EFAULT.
124  */
125 
126 long __weak probe_user_write(void __user *dst, const void *src, size_t size)
127     __attribute__((alias("__probe_user_write")));
128 
__probe_user_write(void __user * dst,const void * src,size_t size)129 long __probe_user_write(void __user *dst, const void *src, size_t size)
130 {
131 	long ret = -EFAULT;
132 	mm_segment_t old_fs = get_fs();
133 
134 	set_fs(USER_DS);
135 	if (access_ok(VERIFY_WRITE, dst, size))
136 		ret = probe_write_common(dst, src, size);
137 	set_fs(old_fs);
138 
139 	return ret;
140 }
141 EXPORT_SYMBOL_GPL(probe_user_write);
142 
143 /**
144  * strncpy_from_unsafe: - Copy a NUL terminated string from unsafe address.
145  * @dst:   Destination address, in kernel space.  This buffer must be at
146  *         least @count bytes long.
147  * @unsafe_addr: Unsafe address.
148  * @count: Maximum number of bytes to copy, including the trailing NUL.
149  *
150  * Copies a NUL-terminated string from unsafe address to kernel buffer.
151  *
152  * On success, returns the length of the string INCLUDING the trailing NUL.
153  *
154  * If access fails, returns -EFAULT (some data may have been copied
155  * and the trailing NUL added).
156  *
157  * If @count is smaller than the length of the string, copies @count-1 bytes,
158  * sets the last byte of @dst buffer to NUL and returns @count.
159  */
strncpy_from_unsafe(char * dst,const void * unsafe_addr,long count)160 long strncpy_from_unsafe(char *dst, const void *unsafe_addr, long count)
161 {
162 	mm_segment_t old_fs = get_fs();
163 	const void *src = unsafe_addr;
164 	long ret;
165 
166 	if (unlikely(count <= 0))
167 		return 0;
168 
169 	set_fs(KERNEL_DS);
170 	pagefault_disable();
171 
172 	do {
173 		ret = __get_user(*dst++, (const char __user __force *)src++);
174 	} while (dst[-1] && ret == 0 && src - unsafe_addr < count);
175 
176 	dst[-1] = '\0';
177 	pagefault_enable();
178 	set_fs(old_fs);
179 
180 	return ret ? -EFAULT : src - unsafe_addr;
181 }
182 
183 /**
184  * strncpy_from_unsafe_user: - Copy a NUL terminated string from unsafe user
185  *				address.
186  * @dst:   Destination address, in kernel space.  This buffer must be at
187  *         least @count bytes long.
188  * @unsafe_addr: Unsafe user address.
189  * @count: Maximum number of bytes to copy, including the trailing NUL.
190  *
191  * Copies a NUL-terminated string from unsafe user address to kernel buffer.
192  *
193  * On success, returns the length of the string INCLUDING the trailing NUL.
194  *
195  * If access fails, returns -EFAULT (some data may have been copied
196  * and the trailing NUL added).
197  *
198  * If @count is smaller than the length of the string, copies @count-1 bytes,
199  * sets the last byte of @dst buffer to NUL and returns @count.
200  */
strncpy_from_unsafe_user(char * dst,const void __user * unsafe_addr,long count)201 long strncpy_from_unsafe_user(char *dst, const void __user *unsafe_addr,
202 			      long count)
203 {
204 	mm_segment_t old_fs = get_fs();
205 	long ret;
206 
207 	if (unlikely(count <= 0))
208 		return 0;
209 
210 	set_fs(USER_DS);
211 	pagefault_disable();
212 	ret = strncpy_from_user(dst, unsafe_addr, count);
213 	pagefault_enable();
214 	set_fs(old_fs);
215 
216 	if (ret >= count) {
217 		ret = count;
218 		dst[ret - 1] = '\0';
219 	} else if (ret > 0) {
220 		ret++;
221 	}
222 
223 	return ret;
224 }
225 
226 /**
227  * strnlen_unsafe_user: - Get the size of a user string INCLUDING final NUL.
228  * @unsafe_addr: The string to measure.
229  * @count: Maximum count (including NUL)
230  *
231  * Get the size of a NUL-terminated string in user space without pagefault.
232  *
233  * Returns the size of the string INCLUDING the terminating NUL.
234  *
235  * If the string is too long, returns a number larger than @count. User
236  * has to check the return value against "> count".
237  * On exception (or invalid count), returns 0.
238  *
239  * Unlike strnlen_user, this can be used from IRQ handler etc. because
240  * it disables pagefaults.
241  */
strnlen_unsafe_user(const void __user * unsafe_addr,long count)242 long strnlen_unsafe_user(const void __user *unsafe_addr, long count)
243 {
244 	mm_segment_t old_fs = get_fs();
245 	int ret;
246 
247 	set_fs(USER_DS);
248 	pagefault_disable();
249 	ret = strnlen_user(unsafe_addr, count);
250 	pagefault_enable();
251 	set_fs(old_fs);
252 
253 	return ret;
254 }
255