LCOV - code coverage report
Current view: top level - fs - fhandle.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 93 0.0 %
Date: 2023-08-24 13:40:31 Functions: 0 9 0.0 %

          Line data    Source code
       1             : // SPDX-License-Identifier: GPL-2.0
       2             : #include <linux/syscalls.h>
       3             : #include <linux/slab.h>
       4             : #include <linux/fs.h>
       5             : #include <linux/file.h>
       6             : #include <linux/mount.h>
       7             : #include <linux/namei.h>
       8             : #include <linux/exportfs.h>
       9             : #include <linux/fs_struct.h>
      10             : #include <linux/fsnotify.h>
      11             : #include <linux/personality.h>
      12             : #include <linux/uaccess.h>
      13             : #include <linux/compat.h>
      14             : #include "internal.h"
      15             : #include "mount.h"
      16             : 
      17           0 : static long do_sys_name_to_handle(const struct path *path,
      18             :                                   struct file_handle __user *ufh,
      19             :                                   int __user *mnt_id, int fh_flags)
      20             : {
      21             :         long retval;
      22             :         struct file_handle f_handle;
      23             :         int handle_dwords, handle_bytes;
      24           0 :         struct file_handle *handle = NULL;
      25             : 
      26             :         /*
      27             :          * We need to make sure whether the file system support decoding of
      28             :          * the file handle if decodeable file handle was requested.
      29             :          * Otherwise, even empty export_operations are sufficient to opt-in
      30             :          * to encoding FIDs.
      31             :          */
      32           0 :         if (!path->dentry->d_sb->s_export_op ||
      33           0 :             (!(fh_flags & EXPORT_FH_FID) &&
      34           0 :              !path->dentry->d_sb->s_export_op->fh_to_dentry))
      35             :                 return -EOPNOTSUPP;
      36             : 
      37           0 :         if (copy_from_user(&f_handle, ufh, sizeof(struct file_handle)))
      38             :                 return -EFAULT;
      39             : 
      40           0 :         if (f_handle.handle_bytes > MAX_HANDLE_SZ)
      41             :                 return -EINVAL;
      42             : 
      43           0 :         handle = kmalloc(sizeof(struct file_handle) + f_handle.handle_bytes,
      44             :                          GFP_KERNEL);
      45           0 :         if (!handle)
      46             :                 return -ENOMEM;
      47             : 
      48             :         /* convert handle size to multiple of sizeof(u32) */
      49           0 :         handle_dwords = f_handle.handle_bytes >> 2;
      50             : 
      51             :         /* we ask for a non connectable maybe decodeable file handle */
      52           0 :         retval = exportfs_encode_fh(path->dentry,
      53           0 :                                     (struct fid *)handle->f_handle,
      54             :                                     &handle_dwords, fh_flags);
      55           0 :         handle->handle_type = retval;
      56             :         /* convert handle size to bytes */
      57           0 :         handle_bytes = handle_dwords * sizeof(u32);
      58           0 :         handle->handle_bytes = handle_bytes;
      59           0 :         if ((handle->handle_bytes > f_handle.handle_bytes) ||
      60           0 :             (retval == FILEID_INVALID) || (retval < 0)) {
      61             :                 /* As per old exportfs_encode_fh documentation
      62             :                  * we could return ENOSPC to indicate overflow
      63             :                  * But file system returned 255 always. So handle
      64             :                  * both the values
      65             :                  */
      66           0 :                 if (retval == FILEID_INVALID || retval == -ENOSPC)
      67           0 :                         retval = -EOVERFLOW;
      68             :                 /*
      69             :                  * set the handle size to zero so we copy only
      70             :                  * non variable part of the file_handle
      71             :                  */
      72             :                 handle_bytes = 0;
      73             :         } else
      74             :                 retval = 0;
      75             :         /* copy the mount id */
      76           0 :         if (put_user(real_mount(path->mnt)->mnt_id, mnt_id) ||
      77           0 :             copy_to_user(ufh, handle,
      78             :                          sizeof(struct file_handle) + handle_bytes))
      79             :                 retval = -EFAULT;
      80           0 :         kfree(handle);
      81           0 :         return retval;
      82             : }
      83             : 
      84             : /**
      85             :  * sys_name_to_handle_at: convert name to handle
      86             :  * @dfd: directory relative to which name is interpreted if not absolute
      87             :  * @name: name that should be converted to handle.
      88             :  * @handle: resulting file handle
      89             :  * @mnt_id: mount id of the file system containing the file
      90             :  * @flag: flag value to indicate whether to follow symlink or not
      91             :  *        and whether a decodable file handle is required.
      92             :  *
      93             :  * @handle->handle_size indicate the space available to store the
      94             :  * variable part of the file handle in bytes. If there is not
      95             :  * enough space, the field is updated to return the minimum
      96             :  * value required.
      97             :  */
      98           0 : SYSCALL_DEFINE5(name_to_handle_at, int, dfd, const char __user *, name,
      99             :                 struct file_handle __user *, handle, int __user *, mnt_id,
     100             :                 int, flag)
     101             : {
     102             :         struct path path;
     103             :         int lookup_flags;
     104             :         int fh_flags;
     105             :         int err;
     106             : 
     107           0 :         if (flag & ~(AT_SYMLINK_FOLLOW | AT_EMPTY_PATH | AT_HANDLE_FID))
     108             :                 return -EINVAL;
     109             : 
     110           0 :         lookup_flags = (flag & AT_SYMLINK_FOLLOW) ? LOOKUP_FOLLOW : 0;
     111           0 :         fh_flags = (flag & AT_HANDLE_FID) ? EXPORT_FH_FID : 0;
     112           0 :         if (flag & AT_EMPTY_PATH)
     113           0 :                 lookup_flags |= LOOKUP_EMPTY;
     114           0 :         err = user_path_at(dfd, name, lookup_flags, &path);
     115           0 :         if (!err) {
     116           0 :                 err = do_sys_name_to_handle(&path, handle, mnt_id, fh_flags);
     117           0 :                 path_put(&path);
     118             :         }
     119           0 :         return err;
     120             : }
     121             : 
     122           0 : static struct vfsmount *get_vfsmount_from_fd(int fd)
     123             : {
     124             :         struct vfsmount *mnt;
     125             : 
     126           0 :         if (fd == AT_FDCWD) {
     127           0 :                 struct fs_struct *fs = current->fs;
     128           0 :                 spin_lock(&fs->lock);
     129           0 :                 mnt = mntget(fs->pwd.mnt);
     130           0 :                 spin_unlock(&fs->lock);
     131             :         } else {
     132           0 :                 struct fd f = fdget(fd);
     133           0 :                 if (!f.file)
     134           0 :                         return ERR_PTR(-EBADF);
     135           0 :                 mnt = mntget(f.file->f_path.mnt);
     136           0 :                 fdput(f);
     137             :         }
     138             :         return mnt;
     139             : }
     140             : 
     141           0 : static int vfs_dentry_acceptable(void *context, struct dentry *dentry)
     142             : {
     143           0 :         return 1;
     144             : }
     145             : 
     146           0 : static int do_handle_to_path(int mountdirfd, struct file_handle *handle,
     147             :                              struct path *path)
     148             : {
     149           0 :         int retval = 0;
     150             :         int handle_dwords;
     151             : 
     152           0 :         path->mnt = get_vfsmount_from_fd(mountdirfd);
     153           0 :         if (IS_ERR(path->mnt)) {
     154           0 :                 retval = PTR_ERR(path->mnt);
     155           0 :                 goto out_err;
     156             :         }
     157             :         /* change the handle size to multiple of sizeof(u32) */
     158           0 :         handle_dwords = handle->handle_bytes >> 2;
     159           0 :         path->dentry = exportfs_decode_fh(path->mnt,
     160           0 :                                           (struct fid *)handle->f_handle,
     161             :                                           handle_dwords, handle->handle_type,
     162             :                                           vfs_dentry_acceptable, NULL);
     163           0 :         if (IS_ERR(path->dentry)) {
     164           0 :                 retval = PTR_ERR(path->dentry);
     165             :                 goto out_mnt;
     166             :         }
     167             :         return 0;
     168             : out_mnt:
     169           0 :         mntput(path->mnt);
     170             : out_err:
     171             :         return retval;
     172             : }
     173             : 
     174           0 : static int handle_to_path(int mountdirfd, struct file_handle __user *ufh,
     175             :                    struct path *path)
     176             : {
     177           0 :         int retval = 0;
     178             :         struct file_handle f_handle;
     179           0 :         struct file_handle *handle = NULL;
     180             : 
     181             :         /*
     182             :          * With handle we don't look at the execute bit on the
     183             :          * directory. Ideally we would like CAP_DAC_SEARCH.
     184             :          * But we don't have that
     185             :          */
     186           0 :         if (!capable(CAP_DAC_READ_SEARCH)) {
     187             :                 retval = -EPERM;
     188             :                 goto out_err;
     189             :         }
     190           0 :         if (copy_from_user(&f_handle, ufh, sizeof(struct file_handle))) {
     191             :                 retval = -EFAULT;
     192             :                 goto out_err;
     193             :         }
     194           0 :         if ((f_handle.handle_bytes > MAX_HANDLE_SZ) ||
     195             :             (f_handle.handle_bytes == 0)) {
     196             :                 retval = -EINVAL;
     197             :                 goto out_err;
     198             :         }
     199           0 :         handle = kmalloc(sizeof(struct file_handle) + f_handle.handle_bytes,
     200             :                          GFP_KERNEL);
     201           0 :         if (!handle) {
     202             :                 retval = -ENOMEM;
     203             :                 goto out_err;
     204             :         }
     205             :         /* copy the full handle */
     206           0 :         *handle = f_handle;
     207           0 :         if (copy_from_user(&handle->f_handle,
     208           0 :                            &ufh->f_handle,
     209           0 :                            f_handle.handle_bytes)) {
     210             :                 retval = -EFAULT;
     211             :                 goto out_handle;
     212             :         }
     213             : 
     214           0 :         retval = do_handle_to_path(mountdirfd, handle, path);
     215             : 
     216             : out_handle:
     217           0 :         kfree(handle);
     218             : out_err:
     219           0 :         return retval;
     220             : }
     221             : 
     222           0 : static long do_handle_open(int mountdirfd, struct file_handle __user *ufh,
     223             :                            int open_flag)
     224             : {
     225           0 :         long retval = 0;
     226             :         struct path path;
     227             :         struct file *file;
     228             :         int fd;
     229             : 
     230           0 :         retval = handle_to_path(mountdirfd, ufh, &path);
     231           0 :         if (retval)
     232             :                 return retval;
     233             : 
     234           0 :         fd = get_unused_fd_flags(open_flag);
     235           0 :         if (fd < 0) {
     236           0 :                 path_put(&path);
     237           0 :                 return fd;
     238             :         }
     239           0 :         file = file_open_root(&path, "", open_flag, 0);
     240           0 :         if (IS_ERR(file)) {
     241           0 :                 put_unused_fd(fd);
     242           0 :                 retval =  PTR_ERR(file);
     243             :         } else {
     244           0 :                 retval = fd;
     245           0 :                 fd_install(fd, file);
     246             :         }
     247           0 :         path_put(&path);
     248           0 :         return retval;
     249             : }
     250             : 
     251             : /**
     252             :  * sys_open_by_handle_at: Open the file handle
     253             :  * @mountdirfd: directory file descriptor
     254             :  * @handle: file handle to be opened
     255             :  * @flags: open flags.
     256             :  *
     257             :  * @mountdirfd indicate the directory file descriptor
     258             :  * of the mount point. file handle is decoded relative
     259             :  * to the vfsmount pointed by the @mountdirfd. @flags
     260             :  * value is same as the open(2) flags.
     261             :  */
     262           0 : SYSCALL_DEFINE3(open_by_handle_at, int, mountdirfd,
     263             :                 struct file_handle __user *, handle,
     264             :                 int, flags)
     265             : {
     266             :         long ret;
     267             : 
     268             :         if (force_o_largefile())
     269           0 :                 flags |= O_LARGEFILE;
     270             : 
     271           0 :         ret = do_handle_open(mountdirfd, handle, flags);
     272             :         return ret;
     273             : }
     274             : 
     275             : #ifdef CONFIG_COMPAT
     276             : /*
     277             :  * Exactly like fs/open.c:sys_open_by_handle_at(), except that it
     278             :  * doesn't set the O_LARGEFILE flag.
     279             :  */
     280             : COMPAT_SYSCALL_DEFINE3(open_by_handle_at, int, mountdirfd,
     281             :                              struct file_handle __user *, handle, int, flags)
     282             : {
     283             :         return do_handle_open(mountdirfd, handle, flags);
     284             : }
     285             : #endif

Generated by: LCOV version 1.14