LCOV - code coverage report
Current view: top level - fs - ioctl.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 319 0.0 %
Date: 2023-04-06 08:38:28 Functions: 0 28 0.0 %

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

Generated by: LCOV version 1.14