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

Generated by: LCOV version 1.14