1
2
3
4#include <linux/export.h>
5#include <linux/mm.h>
6#include <linux/uaccess.h>
7
8static __always_inline long
9probe_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
20static __always_inline long
21probe_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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53long __weak probe_kernel_read(void *dst, const void *src, size_t size)
54 __attribute__((alias("__probe_kernel_read")));
55
56long __weak probe_kernel_read_strict(void *dst, const void *src, size_t size)
57 __attribute__((alias("__probe_kernel_read")));
58
59long __probe_kernel_read(void *dst, const void *src, size_t size)
60{
61 long ret;
62 mm_segment_t old_fs = get_fs();
63
64 set_fs(KERNEL_DS);
65 ret = probe_read_common(dst, (__force const void __user *)src, size);
66 set_fs(old_fs);
67
68 return ret;
69}
70EXPORT_SYMBOL_GPL(probe_kernel_read);
71
72
73
74
75
76
77
78
79
80
81
82long __weak probe_user_read(void *dst, const void __user *src, size_t size)
83 __attribute__((alias("__probe_user_read")));
84
85long __probe_user_read(void *dst, const void __user *src, size_t size)
86{
87 long ret = -EFAULT;
88 mm_segment_t old_fs = get_fs();
89
90 set_fs(USER_DS);
91 if (access_ok(src, size))
92 ret = probe_read_common(dst, src, size);
93 set_fs(old_fs);
94
95 return ret;
96}
97EXPORT_SYMBOL_GPL(probe_user_read);
98
99
100
101
102
103
104
105
106
107
108
109long __weak probe_kernel_write(void *dst, const void *src, size_t size)
110 __attribute__((alias("__probe_kernel_write")));
111
112long __probe_kernel_write(void *dst, const void *src, size_t size)
113{
114 long ret;
115 mm_segment_t old_fs = get_fs();
116
117 set_fs(KERNEL_DS);
118 ret = probe_write_common((__force void __user *)dst, src, size);
119 set_fs(old_fs);
120
121 return ret;
122}
123EXPORT_SYMBOL_GPL(probe_kernel_write);
124
125
126
127
128
129
130
131
132
133
134
135long __weak probe_user_write(void __user *dst, const void *src, size_t size)
136 __attribute__((alias("__probe_user_write")));
137
138long __probe_user_write(void __user *dst, const void *src, size_t size)
139{
140 long ret = -EFAULT;
141 mm_segment_t old_fs = get_fs();
142
143 set_fs(USER_DS);
144 if (access_ok(dst, size))
145 ret = probe_write_common(dst, src, size);
146 set_fs(old_fs);
147
148 return ret;
149}
150EXPORT_SYMBOL_GPL(probe_user_write);
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176long __weak strncpy_from_unsafe(char *dst, const void *unsafe_addr, long count)
177 __attribute__((alias("__strncpy_from_unsafe")));
178
179long __weak strncpy_from_unsafe_strict(char *dst, const void *unsafe_addr,
180 long count)
181 __attribute__((alias("__strncpy_from_unsafe")));
182
183long __strncpy_from_unsafe(char *dst, const void *unsafe_addr, long count)
184{
185 mm_segment_t old_fs = get_fs();
186 const void *src = unsafe_addr;
187 long ret;
188
189 if (unlikely(count <= 0))
190 return 0;
191
192 set_fs(KERNEL_DS);
193 pagefault_disable();
194
195 do {
196 ret = __get_user(*dst++, (const char __user __force *)src++);
197 } while (dst[-1] && ret == 0 && src - unsafe_addr < count);
198
199 dst[-1] = '\0';
200 pagefault_enable();
201 set_fs(old_fs);
202
203 return ret ? -EFAULT : src - unsafe_addr;
204}
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224long strncpy_from_unsafe_user(char *dst, const void __user *unsafe_addr,
225 long count)
226{
227 mm_segment_t old_fs = get_fs();
228 long ret;
229
230 if (unlikely(count <= 0))
231 return 0;
232
233 set_fs(USER_DS);
234 pagefault_disable();
235 ret = strncpy_from_user(dst, unsafe_addr, count);
236 pagefault_enable();
237 set_fs(old_fs);
238
239 if (ret >= count) {
240 ret = count;
241 dst[ret - 1] = '\0';
242 } else if (ret > 0) {
243 ret++;
244 }
245
246 return ret;
247}
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265long strnlen_unsafe_user(const void __user *unsafe_addr, long count)
266{
267 mm_segment_t old_fs = get_fs();
268 int ret;
269
270 set_fs(USER_DS);
271 pagefault_disable();
272 ret = strnlen_user(unsafe_addr, count);
273 pagefault_enable();
274 set_fs(old_fs);
275
276 return ret;
277}
278