1 | // SPDX-License-Identifier: GPL-2.0 |
---|---|
2 | /* |
3 | * linux/fs/ioctl.c |
4 | * |
5 | * Copyright (C) 1991, 1992 Linus Torvalds |
6 | */ |
7 | |
8 | #include <linux/syscalls.h> |
9 | #include <linux/mm.h> |
10 | #include <linux/capability.h> |
11 | #include <linux/compat.h> |
12 | #include <linux/file.h> |
13 | #include <linux/fs.h> |
14 | #include <linux/security.h> |
15 | #include <linux/export.h> |
16 | #include <linux/uaccess.h> |
17 | #include <linux/writeback.h> |
18 | #include <linux/buffer_head.h> |
19 | #include <linux/falloc.h> |
20 | #include <linux/sched/signal.h> |
21 | #include <linux/fiemap.h> |
22 | #include <linux/mount.h> |
23 | #include <linux/fscrypt.h> |
24 | #include <linux/fileattr.h> |
25 | |
26 | #include "internal.h" |
27 | |
28 | #include <asm/ioctls.h> |
29 | |
30 | /* So that the fiemap access checks can't overflow on 32 bit machines. */ |
31 | #define FIEMAP_MAX_EXTENTS (UINT_MAX / sizeof(struct fiemap_extent)) |
32 | |
33 | /** |
34 | * vfs_ioctl - call filesystem specific ioctl methods |
35 | * @filp: open file to invoke ioctl method on |
36 | * @cmd: ioctl command to execute |
37 | * @arg: command-specific argument for ioctl |
38 | * |
39 | * Invokes filesystem specific ->unlocked_ioctl, if one exists; otherwise |
40 | * returns -ENOTTY. |
41 | * |
42 | * Returns 0 on success, -errno on error. |
43 | */ |
44 | long vfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) |
45 | { |
46 | int error = -ENOTTY; |
47 | |
48 | if (!filp->f_op->unlocked_ioctl) |
49 | goto out; |
50 | |
51 | error = filp->f_op->unlocked_ioctl(filp, cmd, arg); |
52 | if (error == -ENOIOCTLCMD) |
53 | error = -ENOTTY; |
54 | out: |
55 | return error; |
56 | } |
57 | EXPORT_SYMBOL(vfs_ioctl); |
58 | |
59 | static int ioctl_fibmap(struct file *filp, int __user *p) |
60 | { |
61 | struct inode *inode = file_inode(f: filp); |
62 | struct super_block *sb = inode->i_sb; |
63 | int error, ur_block; |
64 | sector_t block; |
65 | |
66 | if (!capable(CAP_SYS_RAWIO)) |
67 | return -EPERM; |
68 | |
69 | error = get_user(ur_block, p); |
70 | if (error) |
71 | return error; |
72 | |
73 | if (ur_block < 0) |
74 | return -EINVAL; |
75 | |
76 | block = ur_block; |
77 | error = bmap(inode, block: &block); |
78 | |
79 | if (block > INT_MAX) { |
80 | error = -ERANGE; |
81 | pr_warn_ratelimited("[%s/%d] FS: %s File: %pD4 would truncate fibmap result\n", |
82 | current->comm, task_pid_nr(current), |
83 | sb->s_id, filp); |
84 | } |
85 | |
86 | if (error) |
87 | ur_block = 0; |
88 | else |
89 | ur_block = block; |
90 | |
91 | if (put_user(ur_block, p)) |
92 | error = -EFAULT; |
93 | |
94 | return error; |
95 | } |
96 | |
97 | /** |
98 | * fiemap_fill_next_extent - Fiemap helper function |
99 | * @fieinfo: Fiemap context passed into ->fiemap |
100 | * @logical: Extent logical start offset, in bytes |
101 | * @phys: Extent physical start offset, in bytes |
102 | * @len: Extent length, in bytes |
103 | * @flags: FIEMAP_EXTENT flags that describe this extent |
104 | * |
105 | * Called from file system ->fiemap callback. Will populate extent |
106 | * info as passed in via arguments and copy to user memory. On |
107 | * success, extent count on fieinfo is incremented. |
108 | * |
109 | * Returns 0 on success, -errno on error, 1 if this was the last |
110 | * extent that will fit in user array. |
111 | */ |
112 | int fiemap_fill_next_extent(struct fiemap_extent_info *fieinfo, u64 logical, |
113 | u64 phys, u64 len, u32 flags) |
114 | { |
115 | struct fiemap_extent extent; |
116 | struct fiemap_extent __user *dest = fieinfo->fi_extents_start; |
117 | |
118 | /* only count the extents */ |
119 | if (fieinfo->fi_extents_max == 0) { |
120 | fieinfo->fi_extents_mapped++; |
121 | return (flags & FIEMAP_EXTENT_LAST) ? 1 : 0; |
122 | } |
123 | |
124 | if (fieinfo->fi_extents_mapped >= fieinfo->fi_extents_max) |
125 | return 1; |
126 | |
127 | #define SET_UNKNOWN_FLAGS (FIEMAP_EXTENT_DELALLOC) |
128 | #define SET_NO_UNMOUNTED_IO_FLAGS (FIEMAP_EXTENT_DATA_ENCRYPTED) |
129 | #define SET_NOT_ALIGNED_FLAGS (FIEMAP_EXTENT_DATA_TAIL|FIEMAP_EXTENT_DATA_INLINE) |
130 | |
131 | if (flags & SET_UNKNOWN_FLAGS) |
132 | flags |= FIEMAP_EXTENT_UNKNOWN; |
133 | if (flags & SET_NO_UNMOUNTED_IO_FLAGS) |
134 | flags |= FIEMAP_EXTENT_ENCODED; |
135 | if (flags & SET_NOT_ALIGNED_FLAGS) |
136 | flags |= FIEMAP_EXTENT_NOT_ALIGNED; |
137 | |
138 | memset(&extent, 0, sizeof(extent)); |
139 | extent.fe_logical = logical; |
140 | extent.fe_physical = phys; |
141 | extent.fe_length = len; |
142 | extent.fe_flags = flags; |
143 | |
144 | dest += fieinfo->fi_extents_mapped; |
145 | if (copy_to_user(to: dest, from: &extent, n: sizeof(extent))) |
146 | return -EFAULT; |
147 | |
148 | fieinfo->fi_extents_mapped++; |
149 | if (fieinfo->fi_extents_mapped == fieinfo->fi_extents_max) |
150 | return 1; |
151 | return (flags & FIEMAP_EXTENT_LAST) ? 1 : 0; |
152 | } |
153 | EXPORT_SYMBOL(fiemap_fill_next_extent); |
154 | |
155 | /** |
156 | * fiemap_prep - check validity of requested flags for fiemap |
157 | * @inode: Inode to operate on |
158 | * @fieinfo: Fiemap context passed into ->fiemap |
159 | * @start: Start of the mapped range |
160 | * @len: Length of the mapped range, can be truncated by this function. |
161 | * @supported_flags: Set of fiemap flags that the file system understands |
162 | * |
163 | * This function must be called from each ->fiemap instance to validate the |
164 | * fiemap request against the file system parameters. |
165 | * |
166 | * Returns 0 on success, or a negative error on failure. |
167 | */ |
168 | int fiemap_prep(struct inode *inode, struct fiemap_extent_info *fieinfo, |
169 | u64 start, u64 *len, u32 supported_flags) |
170 | { |
171 | u64 maxbytes = inode->i_sb->s_maxbytes; |
172 | u32 incompat_flags; |
173 | int ret = 0; |
174 | |
175 | if (*len == 0) |
176 | return -EINVAL; |
177 | if (start >= maxbytes) |
178 | return -EFBIG; |
179 | |
180 | /* |
181 | * Shrink request scope to what the fs can actually handle. |
182 | */ |
183 | if (*len > maxbytes || (maxbytes - *len) < start) |
184 | *len = maxbytes - start; |
185 | |
186 | supported_flags |= FIEMAP_FLAG_SYNC; |
187 | supported_flags &= FIEMAP_FLAGS_COMPAT; |
188 | incompat_flags = fieinfo->fi_flags & ~supported_flags; |
189 | if (incompat_flags) { |
190 | fieinfo->fi_flags = incompat_flags; |
191 | return -EBADR; |
192 | } |
193 | |
194 | if (fieinfo->fi_flags & FIEMAP_FLAG_SYNC) |
195 | ret = filemap_write_and_wait(mapping: inode->i_mapping); |
196 | return ret; |
197 | } |
198 | EXPORT_SYMBOL(fiemap_prep); |
199 | |
200 | static int ioctl_fiemap(struct file *filp, struct fiemap __user *ufiemap) |
201 | { |
202 | struct fiemap fiemap; |
203 | struct fiemap_extent_info fieinfo = { 0, }; |
204 | struct inode *inode = file_inode(f: filp); |
205 | int error; |
206 | |
207 | if (!inode->i_op->fiemap) |
208 | return -EOPNOTSUPP; |
209 | |
210 | if (copy_from_user(to: &fiemap, from: ufiemap, n: sizeof(fiemap))) |
211 | return -EFAULT; |
212 | |
213 | if (fiemap.fm_extent_count > FIEMAP_MAX_EXTENTS) |
214 | return -EINVAL; |
215 | |
216 | fieinfo.fi_flags = fiemap.fm_flags; |
217 | fieinfo.fi_extents_max = fiemap.fm_extent_count; |
218 | fieinfo.fi_extents_start = ufiemap->fm_extents; |
219 | |
220 | error = inode->i_op->fiemap(inode, &fieinfo, fiemap.fm_start, |
221 | fiemap.fm_length); |
222 | |
223 | fiemap.fm_flags = fieinfo.fi_flags; |
224 | fiemap.fm_mapped_extents = fieinfo.fi_extents_mapped; |
225 | if (copy_to_user(to: ufiemap, from: &fiemap, n: sizeof(fiemap))) |
226 | error = -EFAULT; |
227 | |
228 | return error; |
229 | } |
230 | |
231 | static long ioctl_file_clone(struct file *dst_file, unsigned long srcfd, |
232 | u64 off, u64 olen, u64 destoff) |
233 | { |
234 | struct fd src_file = fdget(fd: srcfd); |
235 | loff_t cloned; |
236 | int ret; |
237 | |
238 | if (!src_file.file) |
239 | return -EBADF; |
240 | cloned = vfs_clone_file_range(file_in: src_file.file, pos_in: off, file_out: dst_file, pos_out: destoff, |
241 | len: olen, remap_flags: 0); |
242 | if (cloned < 0) |
243 | ret = cloned; |
244 | else if (olen && cloned != olen) |
245 | ret = -EINVAL; |
246 | else |
247 | ret = 0; |
248 | fdput(fd: src_file); |
249 | return ret; |
250 | } |
251 | |
252 | static long ioctl_file_clone_range(struct file *file, |
253 | struct file_clone_range __user *argp) |
254 | { |
255 | struct file_clone_range args; |
256 | |
257 | if (copy_from_user(to: &args, from: argp, n: sizeof(args))) |
258 | return -EFAULT; |
259 | return ioctl_file_clone(dst_file: file, srcfd: args.src_fd, off: args.src_offset, |
260 | olen: args.src_length, destoff: args.dest_offset); |
261 | } |
262 | |
263 | /* |
264 | * This provides compatibility with legacy XFS pre-allocation ioctls |
265 | * which predate the fallocate syscall. |
266 | * |
267 | * Only the l_start, l_len and l_whence fields of the 'struct space_resv' |
268 | * are used here, rest are ignored. |
269 | */ |
270 | static int ioctl_preallocate(struct file *filp, int mode, void __user *argp) |
271 | { |
272 | struct inode *inode = file_inode(f: filp); |
273 | struct space_resv sr; |
274 | |
275 | if (copy_from_user(to: &sr, from: argp, n: sizeof(sr))) |
276 | return -EFAULT; |
277 | |
278 | switch (sr.l_whence) { |
279 | case SEEK_SET: |
280 | break; |
281 | case SEEK_CUR: |
282 | sr.l_start += filp->f_pos; |
283 | break; |
284 | case SEEK_END: |
285 | sr.l_start += i_size_read(inode); |
286 | break; |
287 | default: |
288 | return -EINVAL; |
289 | } |
290 | |
291 | return vfs_fallocate(file: filp, mode: mode | FALLOC_FL_KEEP_SIZE, offset: sr.l_start, |
292 | len: sr.l_len); |
293 | } |
294 | |
295 | /* on ia32 l_start is on a 32-bit boundary */ |
296 | #if defined CONFIG_COMPAT && defined(CONFIG_X86_64) |
297 | /* just account for different alignment */ |
298 | static int compat_ioctl_preallocate(struct file *file, int mode, |
299 | struct space_resv_32 __user *argp) |
300 | { |
301 | struct inode *inode = file_inode(f: file); |
302 | struct space_resv_32 sr; |
303 | |
304 | if (copy_from_user(to: &sr, from: argp, n: sizeof(sr))) |
305 | return -EFAULT; |
306 | |
307 | switch (sr.l_whence) { |
308 | case SEEK_SET: |
309 | break; |
310 | case SEEK_CUR: |
311 | sr.l_start += file->f_pos; |
312 | break; |
313 | case SEEK_END: |
314 | sr.l_start += i_size_read(inode); |
315 | break; |
316 | default: |
317 | return -EINVAL; |
318 | } |
319 | |
320 | return vfs_fallocate(file, mode: mode | FALLOC_FL_KEEP_SIZE, offset: sr.l_start, len: sr.l_len); |
321 | } |
322 | #endif |
323 | |
324 | static int file_ioctl(struct file *filp, unsigned int cmd, int __user *p) |
325 | { |
326 | switch (cmd) { |
327 | case FIBMAP: |
328 | return ioctl_fibmap(filp, p); |
329 | case FS_IOC_RESVSP: |
330 | case FS_IOC_RESVSP64: |
331 | return ioctl_preallocate(filp, mode: 0, argp: p); |
332 | case FS_IOC_UNRESVSP: |
333 | case FS_IOC_UNRESVSP64: |
334 | return ioctl_preallocate(filp, FALLOC_FL_PUNCH_HOLE, argp: p); |
335 | case FS_IOC_ZERO_RANGE: |
336 | return ioctl_preallocate(filp, FALLOC_FL_ZERO_RANGE, argp: p); |
337 | } |
338 | |
339 | return -ENOIOCTLCMD; |
340 | } |
341 | |
342 | static int ioctl_fionbio(struct file *filp, int __user *argp) |
343 | { |
344 | unsigned int flag; |
345 | int on, error; |
346 | |
347 | error = get_user(on, argp); |
348 | if (error) |
349 | return error; |
350 | flag = O_NONBLOCK; |
351 | #ifdef __sparc__ |
352 | /* SunOS compatibility item. */ |
353 | if (O_NONBLOCK != O_NDELAY) |
354 | flag |= O_NDELAY; |
355 | #endif |
356 | spin_lock(lock: &filp->f_lock); |
357 | if (on) |
358 | filp->f_flags |= flag; |
359 | else |
360 | filp->f_flags &= ~flag; |
361 | spin_unlock(lock: &filp->f_lock); |
362 | return error; |
363 | } |
364 | |
365 | static int ioctl_fioasync(unsigned int fd, struct file *filp, |
366 | int __user *argp) |
367 | { |
368 | unsigned int flag; |
369 | int on, error; |
370 | |
371 | error = get_user(on, argp); |
372 | if (error) |
373 | return error; |
374 | flag = on ? FASYNC : 0; |
375 | |
376 | /* Did FASYNC state change ? */ |
377 | if ((flag ^ filp->f_flags) & FASYNC) { |
378 | if (filp->f_op->fasync) |
379 | /* fasync() adjusts filp->f_flags */ |
380 | error = filp->f_op->fasync(fd, filp, on); |
381 | else |
382 | error = -ENOTTY; |
383 | } |
384 | return error < 0 ? error : 0; |
385 | } |
386 | |
387 | static int ioctl_fsfreeze(struct file *filp) |
388 | { |
389 | struct super_block *sb = file_inode(f: filp)->i_sb; |
390 | |
391 | if (!ns_capable(ns: sb->s_user_ns, CAP_SYS_ADMIN)) |
392 | return -EPERM; |
393 | |
394 | /* If filesystem doesn't support freeze feature, return. */ |
395 | if (sb->s_op->freeze_fs == NULL && sb->s_op->freeze_super == NULL) |
396 | return -EOPNOTSUPP; |
397 | |
398 | /* Freeze */ |
399 | if (sb->s_op->freeze_super) |
400 | return sb->s_op->freeze_super(sb, FREEZE_HOLDER_USERSPACE); |
401 | return freeze_super(super: sb, who: FREEZE_HOLDER_USERSPACE); |
402 | } |
403 | |
404 | static int ioctl_fsthaw(struct file *filp) |
405 | { |
406 | struct super_block *sb = file_inode(f: filp)->i_sb; |
407 | |
408 | if (!ns_capable(ns: sb->s_user_ns, CAP_SYS_ADMIN)) |
409 | return -EPERM; |
410 | |
411 | /* Thaw */ |
412 | if (sb->s_op->thaw_super) |
413 | return sb->s_op->thaw_super(sb, FREEZE_HOLDER_USERSPACE); |
414 | return thaw_super(super: sb, who: FREEZE_HOLDER_USERSPACE); |
415 | } |
416 | |
417 | static int ioctl_file_dedupe_range(struct file *file, |
418 | struct file_dedupe_range __user *argp) |
419 | { |
420 | struct file_dedupe_range *same = NULL; |
421 | int ret; |
422 | unsigned long size; |
423 | u16 count; |
424 | |
425 | if (get_user(count, &argp->dest_count)) { |
426 | ret = -EFAULT; |
427 | goto out; |
428 | } |
429 | |
430 | size = offsetof(struct file_dedupe_range, info[count]); |
431 | if (size > PAGE_SIZE) { |
432 | ret = -ENOMEM; |
433 | goto out; |
434 | } |
435 | |
436 | same = memdup_user(argp, size); |
437 | if (IS_ERR(ptr: same)) { |
438 | ret = PTR_ERR(ptr: same); |
439 | same = NULL; |
440 | goto out; |
441 | } |
442 | |
443 | same->dest_count = count; |
444 | ret = vfs_dedupe_file_range(file, same); |
445 | if (ret) |
446 | goto out; |
447 | |
448 | ret = copy_to_user(to: argp, from: same, n: size); |
449 | if (ret) |
450 | ret = -EFAULT; |
451 | |
452 | out: |
453 | kfree(objp: same); |
454 | return ret; |
455 | } |
456 | |
457 | /** |
458 | * fileattr_fill_xflags - initialize fileattr with xflags |
459 | * @fa: fileattr pointer |
460 | * @xflags: FS_XFLAG_* flags |
461 | * |
462 | * Set ->fsx_xflags, ->fsx_valid and ->flags (translated xflags). All |
463 | * other fields are zeroed. |
464 | */ |
465 | void fileattr_fill_xflags(struct fileattr *fa, u32 xflags) |
466 | { |
467 | memset(fa, 0, sizeof(*fa)); |
468 | fa->fsx_valid = true; |
469 | fa->fsx_xflags = xflags; |
470 | if (fa->fsx_xflags & FS_XFLAG_IMMUTABLE) |
471 | fa->flags |= FS_IMMUTABLE_FL; |
472 | if (fa->fsx_xflags & FS_XFLAG_APPEND) |
473 | fa->flags |= FS_APPEND_FL; |
474 | if (fa->fsx_xflags & FS_XFLAG_SYNC) |
475 | fa->flags |= FS_SYNC_FL; |
476 | if (fa->fsx_xflags & FS_XFLAG_NOATIME) |
477 | fa->flags |= FS_NOATIME_FL; |
478 | if (fa->fsx_xflags & FS_XFLAG_NODUMP) |
479 | fa->flags |= FS_NODUMP_FL; |
480 | if (fa->fsx_xflags & FS_XFLAG_DAX) |
481 | fa->flags |= FS_DAX_FL; |
482 | if (fa->fsx_xflags & FS_XFLAG_PROJINHERIT) |
483 | fa->flags |= FS_PROJINHERIT_FL; |
484 | } |
485 | EXPORT_SYMBOL(fileattr_fill_xflags); |
486 | |
487 | /** |
488 | * fileattr_fill_flags - initialize fileattr with flags |
489 | * @fa: fileattr pointer |
490 | * @flags: FS_*_FL flags |
491 | * |
492 | * Set ->flags, ->flags_valid and ->fsx_xflags (translated flags). |
493 | * All other fields are zeroed. |
494 | */ |
495 | void fileattr_fill_flags(struct fileattr *fa, u32 flags) |
496 | { |
497 | memset(fa, 0, sizeof(*fa)); |
498 | fa->flags_valid = true; |
499 | fa->flags = flags; |
500 | if (fa->flags & FS_SYNC_FL) |
501 | fa->fsx_xflags |= FS_XFLAG_SYNC; |
502 | if (fa->flags & FS_IMMUTABLE_FL) |
503 | fa->fsx_xflags |= FS_XFLAG_IMMUTABLE; |
504 | if (fa->flags & FS_APPEND_FL) |
505 | fa->fsx_xflags |= FS_XFLAG_APPEND; |
506 | if (fa->flags & FS_NODUMP_FL) |
507 | fa->fsx_xflags |= FS_XFLAG_NODUMP; |
508 | if (fa->flags & FS_NOATIME_FL) |
509 | fa->fsx_xflags |= FS_XFLAG_NOATIME; |
510 | if (fa->flags & FS_DAX_FL) |
511 | fa->fsx_xflags |= FS_XFLAG_DAX; |
512 | if (fa->flags & FS_PROJINHERIT_FL) |
513 | fa->fsx_xflags |= FS_XFLAG_PROJINHERIT; |
514 | } |
515 | EXPORT_SYMBOL(fileattr_fill_flags); |
516 | |
517 | /** |
518 | * vfs_fileattr_get - retrieve miscellaneous file attributes |
519 | * @dentry: the object to retrieve from |
520 | * @fa: fileattr pointer |
521 | * |
522 | * Call i_op->fileattr_get() callback, if exists. |
523 | * |
524 | * Return: 0 on success, or a negative error on failure. |
525 | */ |
526 | int vfs_fileattr_get(struct dentry *dentry, struct fileattr *fa) |
527 | { |
528 | struct inode *inode = d_inode(dentry); |
529 | |
530 | if (!inode->i_op->fileattr_get) |
531 | return -ENOIOCTLCMD; |
532 | |
533 | return inode->i_op->fileattr_get(dentry, fa); |
534 | } |
535 | EXPORT_SYMBOL(vfs_fileattr_get); |
536 | |
537 | /** |
538 | * copy_fsxattr_to_user - copy fsxattr to userspace. |
539 | * @fa: fileattr pointer |
540 | * @ufa: fsxattr user pointer |
541 | * |
542 | * Return: 0 on success, or -EFAULT on failure. |
543 | */ |
544 | int copy_fsxattr_to_user(const struct fileattr *fa, struct fsxattr __user *ufa) |
545 | { |
546 | struct fsxattr xfa; |
547 | |
548 | memset(&xfa, 0, sizeof(xfa)); |
549 | xfa.fsx_xflags = fa->fsx_xflags; |
550 | xfa.fsx_extsize = fa->fsx_extsize; |
551 | xfa.fsx_nextents = fa->fsx_nextents; |
552 | xfa.fsx_projid = fa->fsx_projid; |
553 | xfa.fsx_cowextsize = fa->fsx_cowextsize; |
554 | |
555 | if (copy_to_user(to: ufa, from: &xfa, n: sizeof(xfa))) |
556 | return -EFAULT; |
557 | |
558 | return 0; |
559 | } |
560 | EXPORT_SYMBOL(copy_fsxattr_to_user); |
561 | |
562 | static int copy_fsxattr_from_user(struct fileattr *fa, |
563 | struct fsxattr __user *ufa) |
564 | { |
565 | struct fsxattr xfa; |
566 | |
567 | if (copy_from_user(to: &xfa, from: ufa, n: sizeof(xfa))) |
568 | return -EFAULT; |
569 | |
570 | fileattr_fill_xflags(fa, xfa.fsx_xflags); |
571 | fa->fsx_extsize = xfa.fsx_extsize; |
572 | fa->fsx_nextents = xfa.fsx_nextents; |
573 | fa->fsx_projid = xfa.fsx_projid; |
574 | fa->fsx_cowextsize = xfa.fsx_cowextsize; |
575 | |
576 | return 0; |
577 | } |
578 | |
579 | /* |
580 | * Generic function to check FS_IOC_FSSETXATTR/FS_IOC_SETFLAGS values and reject |
581 | * any invalid configurations. |
582 | * |
583 | * Note: must be called with inode lock held. |
584 | */ |
585 | static int fileattr_set_prepare(struct inode *inode, |
586 | const struct fileattr *old_ma, |
587 | struct fileattr *fa) |
588 | { |
589 | int err; |
590 | |
591 | /* |
592 | * The IMMUTABLE and APPEND_ONLY flags can only be changed by |
593 | * the relevant capability. |
594 | */ |
595 | if ((fa->flags ^ old_ma->flags) & (FS_APPEND_FL | FS_IMMUTABLE_FL) && |
596 | !capable(CAP_LINUX_IMMUTABLE)) |
597 | return -EPERM; |
598 | |
599 | err = fscrypt_prepare_setflags(inode, oldflags: old_ma->flags, flags: fa->flags); |
600 | if (err) |
601 | return err; |
602 | |
603 | /* |
604 | * Project Quota ID state is only allowed to change from within the init |
605 | * namespace. Enforce that restriction only if we are trying to change |
606 | * the quota ID state. Everything else is allowed in user namespaces. |
607 | */ |
608 | if (current_user_ns() != &init_user_ns) { |
609 | if (old_ma->fsx_projid != fa->fsx_projid) |
610 | return -EINVAL; |
611 | if ((old_ma->fsx_xflags ^ fa->fsx_xflags) & |
612 | FS_XFLAG_PROJINHERIT) |
613 | return -EINVAL; |
614 | } else { |
615 | /* |
616 | * Caller is allowed to change the project ID. If it is being |
617 | * changed, make sure that the new value is valid. |
618 | */ |
619 | if (old_ma->fsx_projid != fa->fsx_projid && |
620 | !projid_valid(projid: make_kprojid(from: &init_user_ns, projid: fa->fsx_projid))) |
621 | return -EINVAL; |
622 | } |
623 | |
624 | /* Check extent size hints. */ |
625 | if ((fa->fsx_xflags & FS_XFLAG_EXTSIZE) && !S_ISREG(inode->i_mode)) |
626 | return -EINVAL; |
627 | |
628 | if ((fa->fsx_xflags & FS_XFLAG_EXTSZINHERIT) && |
629 | !S_ISDIR(inode->i_mode)) |
630 | return -EINVAL; |
631 | |
632 | if ((fa->fsx_xflags & FS_XFLAG_COWEXTSIZE) && |
633 | !S_ISREG(inode->i_mode) && !S_ISDIR(inode->i_mode)) |
634 | return -EINVAL; |
635 | |
636 | /* |
637 | * It is only valid to set the DAX flag on regular files and |
638 | * directories on filesystems. |
639 | */ |
640 | if ((fa->fsx_xflags & FS_XFLAG_DAX) && |
641 | !(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode))) |
642 | return -EINVAL; |
643 | |
644 | /* Extent size hints of zero turn off the flags. */ |
645 | if (fa->fsx_extsize == 0) |
646 | fa->fsx_xflags &= ~(FS_XFLAG_EXTSIZE | FS_XFLAG_EXTSZINHERIT); |
647 | if (fa->fsx_cowextsize == 0) |
648 | fa->fsx_xflags &= ~FS_XFLAG_COWEXTSIZE; |
649 | |
650 | return 0; |
651 | } |
652 | |
653 | /** |
654 | * vfs_fileattr_set - change miscellaneous file attributes |
655 | * @idmap: idmap of the mount |
656 | * @dentry: the object to change |
657 | * @fa: fileattr pointer |
658 | * |
659 | * After verifying permissions, call i_op->fileattr_set() callback, if |
660 | * exists. |
661 | * |
662 | * Verifying attributes involves retrieving current attributes with |
663 | * i_op->fileattr_get(), this also allows initializing attributes that have |
664 | * not been set by the caller to current values. Inode lock is held |
665 | * thoughout to prevent racing with another instance. |
666 | * |
667 | * Return: 0 on success, or a negative error on failure. |
668 | */ |
669 | int vfs_fileattr_set(struct mnt_idmap *idmap, struct dentry *dentry, |
670 | struct fileattr *fa) |
671 | { |
672 | struct inode *inode = d_inode(dentry); |
673 | struct fileattr old_ma = {}; |
674 | int err; |
675 | |
676 | if (!inode->i_op->fileattr_set) |
677 | return -ENOIOCTLCMD; |
678 | |
679 | if (!inode_owner_or_capable(idmap, inode)) |
680 | return -EPERM; |
681 | |
682 | inode_lock(inode); |
683 | err = vfs_fileattr_get(dentry, &old_ma); |
684 | if (!err) { |
685 | /* initialize missing bits from old_ma */ |
686 | if (fa->flags_valid) { |
687 | fa->fsx_xflags |= old_ma.fsx_xflags & ~FS_XFLAG_COMMON; |
688 | fa->fsx_extsize = old_ma.fsx_extsize; |
689 | fa->fsx_nextents = old_ma.fsx_nextents; |
690 | fa->fsx_projid = old_ma.fsx_projid; |
691 | fa->fsx_cowextsize = old_ma.fsx_cowextsize; |
692 | } else { |
693 | fa->flags |= old_ma.flags & ~FS_COMMON_FL; |
694 | } |
695 | err = fileattr_set_prepare(inode, old_ma: &old_ma, fa); |
696 | if (!err) |
697 | err = inode->i_op->fileattr_set(idmap, dentry, fa); |
698 | } |
699 | inode_unlock(inode); |
700 | |
701 | return err; |
702 | } |
703 | EXPORT_SYMBOL(vfs_fileattr_set); |
704 | |
705 | static int ioctl_getflags(struct file *file, unsigned int __user *argp) |
706 | { |
707 | struct fileattr fa = { .flags_valid = true }; /* hint only */ |
708 | int err; |
709 | |
710 | err = vfs_fileattr_get(file->f_path.dentry, &fa); |
711 | if (!err) |
712 | err = put_user(fa.flags, argp); |
713 | return err; |
714 | } |
715 | |
716 | static int ioctl_setflags(struct file *file, unsigned int __user *argp) |
717 | { |
718 | struct mnt_idmap *idmap = file_mnt_idmap(file); |
719 | struct dentry *dentry = file->f_path.dentry; |
720 | struct fileattr fa; |
721 | unsigned int flags; |
722 | int err; |
723 | |
724 | err = get_user(flags, argp); |
725 | if (!err) { |
726 | err = mnt_want_write_file(file); |
727 | if (!err) { |
728 | fileattr_fill_flags(&fa, flags); |
729 | err = vfs_fileattr_set(idmap, dentry, &fa); |
730 | mnt_drop_write_file(file); |
731 | } |
732 | } |
733 | return err; |
734 | } |
735 | |
736 | static int ioctl_fsgetxattr(struct file *file, void __user *argp) |
737 | { |
738 | struct fileattr fa = { .fsx_valid = true }; /* hint only */ |
739 | int err; |
740 | |
741 | err = vfs_fileattr_get(file->f_path.dentry, &fa); |
742 | if (!err) |
743 | err = copy_fsxattr_to_user(&fa, argp); |
744 | |
745 | return err; |
746 | } |
747 | |
748 | static int ioctl_fssetxattr(struct file *file, void __user *argp) |
749 | { |
750 | struct mnt_idmap *idmap = file_mnt_idmap(file); |
751 | struct dentry *dentry = file->f_path.dentry; |
752 | struct fileattr fa; |
753 | int err; |
754 | |
755 | err = copy_fsxattr_from_user(fa: &fa, ufa: argp); |
756 | if (!err) { |
757 | err = mnt_want_write_file(file); |
758 | if (!err) { |
759 | err = vfs_fileattr_set(idmap, dentry, &fa); |
760 | mnt_drop_write_file(file); |
761 | } |
762 | } |
763 | return err; |
764 | } |
765 | |
766 | static int ioctl_getfsuuid(struct file *file, void __user *argp) |
767 | { |
768 | struct super_block *sb = file_inode(f: file)->i_sb; |
769 | struct fsuuid2 u = { .len = sb->s_uuid_len, }; |
770 | |
771 | if (!sb->s_uuid_len) |
772 | return -ENOIOCTLCMD; |
773 | |
774 | memcpy(&u.uuid[0], &sb->s_uuid, sb->s_uuid_len); |
775 | |
776 | return copy_to_user(to: argp, from: &u, n: sizeof(u)) ? -EFAULT : 0; |
777 | } |
778 | |
779 | static int ioctl_get_fs_sysfs_path(struct file *file, void __user *argp) |
780 | { |
781 | struct super_block *sb = file_inode(f: file)->i_sb; |
782 | |
783 | if (!strlen(sb->s_sysfs_name)) |
784 | return -ENOIOCTLCMD; |
785 | |
786 | struct fs_sysfs_path u = {}; |
787 | |
788 | u.len = scnprintf(buf: u.name, size: sizeof(u.name), fmt: "%s/%s", sb->s_type->name, sb->s_sysfs_name); |
789 | |
790 | return copy_to_user(to: argp, from: &u, n: sizeof(u)) ? -EFAULT : 0; |
791 | } |
792 | |
793 | /* |
794 | * do_vfs_ioctl() is not for drivers and not intended to be EXPORT_SYMBOL()'d. |
795 | * It's just a simple helper for sys_ioctl and compat_sys_ioctl. |
796 | * |
797 | * When you add any new common ioctls to the switches above and below, |
798 | * please ensure they have compatible arguments in compat mode. |
799 | */ |
800 | static int do_vfs_ioctl(struct file *filp, unsigned int fd, |
801 | unsigned int cmd, unsigned long arg) |
802 | { |
803 | void __user *argp = (void __user *)arg; |
804 | struct inode *inode = file_inode(f: filp); |
805 | |
806 | switch (cmd) { |
807 | case FIOCLEX: |
808 | set_close_on_exec(fd, flag: 1); |
809 | return 0; |
810 | |
811 | case FIONCLEX: |
812 | set_close_on_exec(fd, flag: 0); |
813 | return 0; |
814 | |
815 | case FIONBIO: |
816 | return ioctl_fionbio(filp, argp); |
817 | |
818 | case FIOASYNC: |
819 | return ioctl_fioasync(fd, filp, argp); |
820 | |
821 | case FIOQSIZE: |
822 | if (S_ISDIR(inode->i_mode) || S_ISREG(inode->i_mode) || |
823 | S_ISLNK(inode->i_mode)) { |
824 | loff_t res = inode_get_bytes(inode); |
825 | return copy_to_user(to: argp, from: &res, n: sizeof(res)) ? |
826 | -EFAULT : 0; |
827 | } |
828 | |
829 | return -ENOTTY; |
830 | |
831 | case FIFREEZE: |
832 | return ioctl_fsfreeze(filp); |
833 | |
834 | case FITHAW: |
835 | return ioctl_fsthaw(filp); |
836 | |
837 | case FS_IOC_FIEMAP: |
838 | return ioctl_fiemap(filp, ufiemap: argp); |
839 | |
840 | case FIGETBSZ: |
841 | /* anon_bdev filesystems may not have a block size */ |
842 | if (!inode->i_sb->s_blocksize) |
843 | return -EINVAL; |
844 | |
845 | return put_user(inode->i_sb->s_blocksize, (int __user *)argp); |
846 | |
847 | case FICLONE: |
848 | return ioctl_file_clone(dst_file: filp, srcfd: arg, off: 0, olen: 0, destoff: 0); |
849 | |
850 | case FICLONERANGE: |
851 | return ioctl_file_clone_range(file: filp, argp); |
852 | |
853 | case FIDEDUPERANGE: |
854 | return ioctl_file_dedupe_range(file: filp, argp); |
855 | |
856 | case FIONREAD: |
857 | if (!S_ISREG(inode->i_mode)) |
858 | return vfs_ioctl(filp, cmd, arg); |
859 | |
860 | return put_user(i_size_read(inode) - filp->f_pos, |
861 | (int __user *)argp); |
862 | |
863 | case FS_IOC_GETFLAGS: |
864 | return ioctl_getflags(file: filp, argp); |
865 | |
866 | case FS_IOC_SETFLAGS: |
867 | return ioctl_setflags(file: filp, argp); |
868 | |
869 | case FS_IOC_FSGETXATTR: |
870 | return ioctl_fsgetxattr(file: filp, argp); |
871 | |
872 | case FS_IOC_FSSETXATTR: |
873 | return ioctl_fssetxattr(file: filp, argp); |
874 | |
875 | case FS_IOC_GETFSUUID: |
876 | return ioctl_getfsuuid(file: filp, argp); |
877 | |
878 | case FS_IOC_GETFSSYSFSPATH: |
879 | return ioctl_get_fs_sysfs_path(file: filp, argp); |
880 | |
881 | default: |
882 | if (S_ISREG(inode->i_mode)) |
883 | return file_ioctl(filp, cmd, p: argp); |
884 | break; |
885 | } |
886 | |
887 | return -ENOIOCTLCMD; |
888 | } |
889 | |
890 | SYSCALL_DEFINE3(ioctl, unsigned int, fd, unsigned int, cmd, unsigned long, arg) |
891 | { |
892 | struct fd f = fdget(fd); |
893 | int error; |
894 | |
895 | if (!f.file) |
896 | return -EBADF; |
897 | |
898 | error = security_file_ioctl(file: f.file, cmd, arg); |
899 | if (error) |
900 | goto out; |
901 | |
902 | error = do_vfs_ioctl(filp: f.file, fd, cmd, arg); |
903 | if (error == -ENOIOCTLCMD) |
904 | error = vfs_ioctl(f.file, cmd, arg); |
905 | |
906 | out: |
907 | fdput(fd: f); |
908 | return error; |
909 | } |
910 | |
911 | #ifdef CONFIG_COMPAT |
912 | /** |
913 | * compat_ptr_ioctl - generic implementation of .compat_ioctl file operation |
914 | * @file: The file to operate on. |
915 | * @cmd: The ioctl command number. |
916 | * @arg: The argument to the ioctl. |
917 | * |
918 | * This is not normally called as a function, but instead set in struct |
919 | * file_operations as |
920 | * |
921 | * .compat_ioctl = compat_ptr_ioctl, |
922 | * |
923 | * On most architectures, the compat_ptr_ioctl() just passes all arguments |
924 | * to the corresponding ->ioctl handler. The exception is arch/s390, where |
925 | * compat_ptr() clears the top bit of a 32-bit pointer value, so user space |
926 | * pointers to the second 2GB alias the first 2GB, as is the case for |
927 | * native 32-bit s390 user space. |
928 | * |
929 | * The compat_ptr_ioctl() function must therefore be used only with ioctl |
930 | * functions that either ignore the argument or pass a pointer to a |
931 | * compatible data type. |
932 | * |
933 | * If any ioctl command handled by fops->unlocked_ioctl passes a plain |
934 | * integer instead of a pointer, or any of the passed data types |
935 | * is incompatible between 32-bit and 64-bit architectures, a proper |
936 | * handler is required instead of compat_ptr_ioctl. |
937 | */ |
938 | long compat_ptr_ioctl(struct file *file, unsigned int cmd, unsigned long arg) |
939 | { |
940 | if (!file->f_op->unlocked_ioctl) |
941 | return -ENOIOCTLCMD; |
942 | |
943 | return file->f_op->unlocked_ioctl(file, cmd, (unsigned long)compat_ptr(uptr: arg)); |
944 | } |
945 | EXPORT_SYMBOL(compat_ptr_ioctl); |
946 | |
947 | COMPAT_SYSCALL_DEFINE3(ioctl, unsigned int, fd, unsigned int, cmd, |
948 | compat_ulong_t, arg) |
949 | { |
950 | struct fd f = fdget(fd); |
951 | int error; |
952 | |
953 | if (!f.file) |
954 | return -EBADF; |
955 | |
956 | error = security_file_ioctl_compat(file: f.file, cmd, arg); |
957 | if (error) |
958 | goto out; |
959 | |
960 | switch (cmd) { |
961 | /* FICLONE takes an int argument, so don't use compat_ptr() */ |
962 | case FICLONE: |
963 | error = ioctl_file_clone(dst_file: f.file, srcfd: arg, off: 0, olen: 0, destoff: 0); |
964 | break; |
965 | |
966 | #if defined(CONFIG_X86_64) |
967 | /* these get messy on amd64 due to alignment differences */ |
968 | case FS_IOC_RESVSP_32: |
969 | case FS_IOC_RESVSP64_32: |
970 | error = compat_ioctl_preallocate(file: f.file, mode: 0, argp: compat_ptr(uptr: arg)); |
971 | break; |
972 | case FS_IOC_UNRESVSP_32: |
973 | case FS_IOC_UNRESVSP64_32: |
974 | error = compat_ioctl_preallocate(file: f.file, FALLOC_FL_PUNCH_HOLE, |
975 | argp: compat_ptr(uptr: arg)); |
976 | break; |
977 | case FS_IOC_ZERO_RANGE_32: |
978 | error = compat_ioctl_preallocate(file: f.file, FALLOC_FL_ZERO_RANGE, |
979 | argp: compat_ptr(uptr: arg)); |
980 | break; |
981 | #endif |
982 | |
983 | /* |
984 | * These access 32-bit values anyway so no further handling is |
985 | * necessary. |
986 | */ |
987 | case FS_IOC32_GETFLAGS: |
988 | case FS_IOC32_SETFLAGS: |
989 | cmd = (cmd == FS_IOC32_GETFLAGS) ? |
990 | FS_IOC_GETFLAGS : FS_IOC_SETFLAGS; |
991 | fallthrough; |
992 | /* |
993 | * everything else in do_vfs_ioctl() takes either a compatible |
994 | * pointer argument or no argument -- call it with a modified |
995 | * argument. |
996 | */ |
997 | default: |
998 | error = do_vfs_ioctl(filp: f.file, fd, cmd, |
999 | arg: (unsigned long)compat_ptr(uptr: arg)); |
1000 | if (error != -ENOIOCTLCMD) |
1001 | break; |
1002 | |
1003 | if (f.file->f_op->compat_ioctl) |
1004 | error = f.file->f_op->compat_ioctl(f.file, cmd, arg); |
1005 | if (error == -ENOIOCTLCMD) |
1006 | error = -ENOTTY; |
1007 | break; |
1008 | } |
1009 | |
1010 | out: |
1011 | fdput(fd: f); |
1012 | |
1013 | return error; |
1014 | } |
1015 | #endif |
1016 |
Definitions
- vfs_ioctl
- ioctl_fibmap
- fiemap_fill_next_extent
- fiemap_prep
- ioctl_fiemap
- ioctl_file_clone
- ioctl_file_clone_range
- ioctl_preallocate
- compat_ioctl_preallocate
- file_ioctl
- ioctl_fionbio
- ioctl_fioasync
- ioctl_fsfreeze
- ioctl_fsthaw
- ioctl_file_dedupe_range
- fileattr_fill_xflags
- fileattr_fill_flags
- vfs_fileattr_get
- copy_fsxattr_to_user
- copy_fsxattr_from_user
- fileattr_set_prepare
- vfs_fileattr_set
- ioctl_getflags
- ioctl_setflags
- ioctl_fsgetxattr
- ioctl_fssetxattr
- ioctl_getfsuuid
- ioctl_get_fs_sysfs_path
- do_vfs_ioctl
Improve your Profiling and Debugging skills
Find out more