1
2
3
4
5
6#include "fuse_i.h"
7
8#include <linux/uio.h>
9#include <linux/compat.h>
10#include <linux/fileattr.h>
11
12
13
14
15
16
17
18static int fuse_copy_ioctl_iovec_old(struct iovec *dst, void *src,
19 size_t transferred, unsigned count,
20 bool is_compat)
21{
22#ifdef CONFIG_COMPAT
23 if (count * sizeof(struct compat_iovec) == transferred) {
24 struct compat_iovec *ciov = src;
25 unsigned i;
26
27
28
29
30
31
32 if (!is_compat)
33 return -EINVAL;
34
35 for (i = 0; i < count; i++) {
36 dst[i].iov_base = compat_ptr(ciov[i].iov_base);
37 dst[i].iov_len = ciov[i].iov_len;
38 }
39 return 0;
40 }
41#endif
42
43 if (count * sizeof(struct iovec) != transferred)
44 return -EIO;
45
46 memcpy(dst, src, transferred);
47 return 0;
48}
49
50
51static int fuse_verify_ioctl_iov(struct fuse_conn *fc, struct iovec *iov,
52 size_t count)
53{
54 size_t n;
55 u32 max = fc->max_pages << PAGE_SHIFT;
56
57 for (n = 0; n < count; n++, iov++) {
58 if (iov->iov_len > (size_t) max)
59 return -ENOMEM;
60 max -= iov->iov_len;
61 }
62 return 0;
63}
64
65static int fuse_copy_ioctl_iovec(struct fuse_conn *fc, struct iovec *dst,
66 void *src, size_t transferred, unsigned count,
67 bool is_compat)
68{
69 unsigned i;
70 struct fuse_ioctl_iovec *fiov = src;
71
72 if (fc->minor < 16) {
73 return fuse_copy_ioctl_iovec_old(dst, src, transferred,
74 count, is_compat);
75 }
76
77 if (count * sizeof(struct fuse_ioctl_iovec) != transferred)
78 return -EIO;
79
80 for (i = 0; i < count; i++) {
81
82 if (fiov[i].base != (unsigned long) fiov[i].base ||
83 fiov[i].len != (unsigned long) fiov[i].len)
84 return -EIO;
85
86 dst[i].iov_base = (void __user *) (unsigned long) fiov[i].base;
87 dst[i].iov_len = (size_t) fiov[i].len;
88
89#ifdef CONFIG_COMPAT
90 if (is_compat &&
91 (ptr_to_compat(dst[i].iov_base) != fiov[i].base ||
92 (compat_size_t) dst[i].iov_len != fiov[i].len))
93 return -EIO;
94#endif
95 }
96
97 return 0;
98}
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147long fuse_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg,
148 unsigned int flags)
149{
150 struct fuse_file *ff = file->private_data;
151 struct fuse_mount *fm = ff->fm;
152 struct fuse_ioctl_in inarg = {
153 .fh = ff->fh,
154 .cmd = cmd,
155 .arg = arg,
156 .flags = flags
157 };
158 struct fuse_ioctl_out outarg;
159 struct iovec *iov_page = NULL;
160 struct iovec *in_iov = NULL, *out_iov = NULL;
161 unsigned int in_iovs = 0, out_iovs = 0, max_pages;
162 size_t in_size, out_size, c;
163 ssize_t transferred;
164 int err, i;
165 struct iov_iter ii;
166 struct fuse_args_pages ap = {};
167
168#if BITS_PER_LONG == 32
169 inarg.flags |= FUSE_IOCTL_32BIT;
170#else
171 if (flags & FUSE_IOCTL_COMPAT) {
172 inarg.flags |= FUSE_IOCTL_32BIT;
173#ifdef CONFIG_X86_X32
174 if (in_x32_syscall())
175 inarg.flags |= FUSE_IOCTL_COMPAT_X32;
176#endif
177 }
178#endif
179
180
181 BUILD_BUG_ON(sizeof(struct fuse_ioctl_iovec) * FUSE_IOCTL_MAX_IOV > PAGE_SIZE);
182
183 err = -ENOMEM;
184 ap.pages = fuse_pages_alloc(fm->fc->max_pages, GFP_KERNEL, &ap.descs);
185 iov_page = (struct iovec *) __get_free_page(GFP_KERNEL);
186 if (!ap.pages || !iov_page)
187 goto out;
188
189 fuse_page_descs_length_init(ap.descs, 0, fm->fc->max_pages);
190
191
192
193
194
195 if (!(flags & FUSE_IOCTL_UNRESTRICTED)) {
196 struct iovec *iov = iov_page;
197
198 iov->iov_base = (void __user *)arg;
199 iov->iov_len = _IOC_SIZE(cmd);
200
201 if (_IOC_DIR(cmd) & _IOC_WRITE) {
202 in_iov = iov;
203 in_iovs = 1;
204 }
205
206 if (_IOC_DIR(cmd) & _IOC_READ) {
207 out_iov = iov;
208 out_iovs = 1;
209 }
210 }
211
212 retry:
213 inarg.in_size = in_size = iov_length(in_iov, in_iovs);
214 inarg.out_size = out_size = iov_length(out_iov, out_iovs);
215
216
217
218
219
220 out_size = max_t(size_t, out_size, PAGE_SIZE);
221 max_pages = DIV_ROUND_UP(max(in_size, out_size), PAGE_SIZE);
222
223
224 err = -ENOMEM;
225 if (max_pages > fm->fc->max_pages)
226 goto out;
227 while (ap.num_pages < max_pages) {
228 ap.pages[ap.num_pages] = alloc_page(GFP_KERNEL | __GFP_HIGHMEM);
229 if (!ap.pages[ap.num_pages])
230 goto out;
231 ap.num_pages++;
232 }
233
234
235
236 ap.args.opcode = FUSE_IOCTL;
237 ap.args.nodeid = ff->nodeid;
238 ap.args.in_numargs = 1;
239 ap.args.in_args[0].size = sizeof(inarg);
240 ap.args.in_args[0].value = &inarg;
241 if (in_size) {
242 ap.args.in_numargs++;
243 ap.args.in_args[1].size = in_size;
244 ap.args.in_pages = true;
245
246 err = -EFAULT;
247 iov_iter_init(&ii, WRITE, in_iov, in_iovs, in_size);
248 for (i = 0; iov_iter_count(&ii) && !WARN_ON(i >= ap.num_pages); i++) {
249 c = copy_page_from_iter(ap.pages[i], 0, PAGE_SIZE, &ii);
250 if (c != PAGE_SIZE && iov_iter_count(&ii))
251 goto out;
252 }
253 }
254
255 ap.args.out_numargs = 2;
256 ap.args.out_args[0].size = sizeof(outarg);
257 ap.args.out_args[0].value = &outarg;
258 ap.args.out_args[1].size = out_size;
259 ap.args.out_pages = true;
260 ap.args.out_argvar = true;
261
262 transferred = fuse_simple_request(fm, &ap.args);
263 err = transferred;
264 if (transferred < 0)
265 goto out;
266
267
268 if (outarg.flags & FUSE_IOCTL_RETRY) {
269 void *vaddr;
270
271
272 err = -EIO;
273 if (!(flags & FUSE_IOCTL_UNRESTRICTED))
274 goto out;
275
276 in_iovs = outarg.in_iovs;
277 out_iovs = outarg.out_iovs;
278
279
280
281
282
283 err = -ENOMEM;
284 if (in_iovs > FUSE_IOCTL_MAX_IOV ||
285 out_iovs > FUSE_IOCTL_MAX_IOV ||
286 in_iovs + out_iovs > FUSE_IOCTL_MAX_IOV)
287 goto out;
288
289 vaddr = kmap_atomic(ap.pages[0]);
290 err = fuse_copy_ioctl_iovec(fm->fc, iov_page, vaddr,
291 transferred, in_iovs + out_iovs,
292 (flags & FUSE_IOCTL_COMPAT) != 0);
293 kunmap_atomic(vaddr);
294 if (err)
295 goto out;
296
297 in_iov = iov_page;
298 out_iov = in_iov + in_iovs;
299
300 err = fuse_verify_ioctl_iov(fm->fc, in_iov, in_iovs);
301 if (err)
302 goto out;
303
304 err = fuse_verify_ioctl_iov(fm->fc, out_iov, out_iovs);
305 if (err)
306 goto out;
307
308 goto retry;
309 }
310
311 err = -EIO;
312 if (transferred > inarg.out_size)
313 goto out;
314
315 err = -EFAULT;
316 iov_iter_init(&ii, READ, out_iov, out_iovs, transferred);
317 for (i = 0; iov_iter_count(&ii) && !WARN_ON(i >= ap.num_pages); i++) {
318 c = copy_page_to_iter(ap.pages[i], 0, PAGE_SIZE, &ii);
319 if (c != PAGE_SIZE && iov_iter_count(&ii))
320 goto out;
321 }
322 err = 0;
323 out:
324 free_page((unsigned long) iov_page);
325 while (ap.num_pages)
326 __free_page(ap.pages[--ap.num_pages]);
327 kfree(ap.pages);
328
329 return err ? err : outarg.result;
330}
331EXPORT_SYMBOL_GPL(fuse_do_ioctl);
332
333long fuse_ioctl_common(struct file *file, unsigned int cmd,
334 unsigned long arg, unsigned int flags)
335{
336 struct inode *inode = file_inode(file);
337 struct fuse_conn *fc = get_fuse_conn(inode);
338
339 if (!fuse_allow_current_process(fc))
340 return -EACCES;
341
342 if (fuse_is_bad(inode))
343 return -EIO;
344
345 return fuse_do_ioctl(file, cmd, arg, flags);
346}
347
348long fuse_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
349{
350 return fuse_ioctl_common(file, cmd, arg, 0);
351}
352
353long fuse_file_compat_ioctl(struct file *file, unsigned int cmd,
354 unsigned long arg)
355{
356 return fuse_ioctl_common(file, cmd, arg, FUSE_IOCTL_COMPAT);
357}
358
359static int fuse_priv_ioctl(struct inode *inode, struct fuse_file *ff,
360 unsigned int cmd, void *ptr, size_t size)
361{
362 struct fuse_mount *fm = ff->fm;
363 struct fuse_ioctl_in inarg;
364 struct fuse_ioctl_out outarg;
365 FUSE_ARGS(args);
366 int err;
367
368 memset(&inarg, 0, sizeof(inarg));
369 inarg.fh = ff->fh;
370 inarg.cmd = cmd;
371
372#if BITS_PER_LONG == 32
373 inarg.flags |= FUSE_IOCTL_32BIT;
374#endif
375 if (S_ISDIR(inode->i_mode))
376 inarg.flags |= FUSE_IOCTL_DIR;
377
378 if (_IOC_DIR(cmd) & _IOC_READ)
379 inarg.out_size = size;
380 if (_IOC_DIR(cmd) & _IOC_WRITE)
381 inarg.in_size = size;
382
383 args.opcode = FUSE_IOCTL;
384 args.nodeid = ff->nodeid;
385 args.in_numargs = 2;
386 args.in_args[0].size = sizeof(inarg);
387 args.in_args[0].value = &inarg;
388 args.in_args[1].size = inarg.in_size;
389 args.in_args[1].value = ptr;
390 args.out_numargs = 2;
391 args.out_args[0].size = sizeof(outarg);
392 args.out_args[0].value = &outarg;
393 args.out_args[1].size = inarg.out_size;
394 args.out_args[1].value = ptr;
395
396 err = fuse_simple_request(fm, &args);
397 if (!err && outarg.flags & FUSE_IOCTL_RETRY)
398 err = -EIO;
399
400 return err;
401}
402
403static struct fuse_file *fuse_priv_ioctl_prepare(struct inode *inode)
404{
405 struct fuse_mount *fm = get_fuse_mount(inode);
406 bool isdir = S_ISDIR(inode->i_mode);
407
408 if (!S_ISREG(inode->i_mode) && !isdir)
409 return ERR_PTR(-ENOTTY);
410
411 return fuse_file_open(fm, get_node_id(inode), O_RDONLY, isdir);
412}
413
414static void fuse_priv_ioctl_cleanup(struct inode *inode, struct fuse_file *ff)
415{
416 fuse_file_release(inode, ff, O_RDONLY, NULL, S_ISDIR(inode->i_mode));
417}
418
419int fuse_fileattr_get(struct dentry *dentry, struct fileattr *fa)
420{
421 struct inode *inode = d_inode(dentry);
422 struct fuse_file *ff;
423 unsigned int flags;
424 struct fsxattr xfa;
425 int err;
426
427 ff = fuse_priv_ioctl_prepare(inode);
428 if (IS_ERR(ff))
429 return PTR_ERR(ff);
430
431 if (fa->flags_valid) {
432 err = fuse_priv_ioctl(inode, ff, FS_IOC_GETFLAGS,
433 &flags, sizeof(flags));
434 if (err)
435 goto cleanup;
436
437 fileattr_fill_flags(fa, flags);
438 } else {
439 err = fuse_priv_ioctl(inode, ff, FS_IOC_FSGETXATTR,
440 &xfa, sizeof(xfa));
441 if (err)
442 goto cleanup;
443
444 fileattr_fill_xflags(fa, xfa.fsx_xflags);
445 fa->fsx_extsize = xfa.fsx_extsize;
446 fa->fsx_nextents = xfa.fsx_nextents;
447 fa->fsx_projid = xfa.fsx_projid;
448 fa->fsx_cowextsize = xfa.fsx_cowextsize;
449 }
450cleanup:
451 fuse_priv_ioctl_cleanup(inode, ff);
452
453 return err;
454}
455
456int fuse_fileattr_set(struct user_namespace *mnt_userns,
457 struct dentry *dentry, struct fileattr *fa)
458{
459 struct inode *inode = d_inode(dentry);
460 struct fuse_file *ff;
461 unsigned int flags = fa->flags;
462 struct fsxattr xfa;
463 int err;
464
465 ff = fuse_priv_ioctl_prepare(inode);
466 if (IS_ERR(ff))
467 return PTR_ERR(ff);
468
469 if (fa->flags_valid) {
470 err = fuse_priv_ioctl(inode, ff, FS_IOC_SETFLAGS,
471 &flags, sizeof(flags));
472 if (err)
473 goto cleanup;
474 } else {
475 memset(&xfa, 0, sizeof(xfa));
476 xfa.fsx_xflags = fa->fsx_xflags;
477 xfa.fsx_extsize = fa->fsx_extsize;
478 xfa.fsx_nextents = fa->fsx_nextents;
479 xfa.fsx_projid = fa->fsx_projid;
480 xfa.fsx_cowextsize = fa->fsx_cowextsize;
481
482 err = fuse_priv_ioctl(inode, ff, FS_IOC_FSSETXATTR,
483 &xfa, sizeof(xfa));
484 }
485
486cleanup:
487 fuse_priv_ioctl_cleanup(inode, ff);
488
489 return err;
490}
491