Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 #include <linux/syscalls.h>
0003 #include <linux/slab.h>
0004 #include <linux/fs.h>
0005 #include <linux/file.h>
0006 #include <linux/mount.h>
0007 #include <linux/namei.h>
0008 #include <linux/exportfs.h>
0009 #include <linux/fs_struct.h>
0010 #include <linux/fsnotify.h>
0011 #include <linux/personality.h>
0012 #include <linux/uaccess.h>
0013 #include <linux/compat.h>
0014 #include "internal.h"
0015 #include "mount.h"
0016 
0017 static long do_sys_name_to_handle(struct path *path,
0018                   struct file_handle __user *ufh,
0019                   int __user *mnt_id)
0020 {
0021     long retval;
0022     struct file_handle f_handle;
0023     int handle_dwords, handle_bytes;
0024     struct file_handle *handle = NULL;
0025 
0026     /*
0027      * We need to make sure whether the file system
0028      * support decoding of the file handle
0029      */
0030     if (!path->dentry->d_sb->s_export_op ||
0031         !path->dentry->d_sb->s_export_op->fh_to_dentry)
0032         return -EOPNOTSUPP;
0033 
0034     if (copy_from_user(&f_handle, ufh, sizeof(struct file_handle)))
0035         return -EFAULT;
0036 
0037     if (f_handle.handle_bytes > MAX_HANDLE_SZ)
0038         return -EINVAL;
0039 
0040     handle = kmalloc(sizeof(struct file_handle) + f_handle.handle_bytes,
0041              GFP_KERNEL);
0042     if (!handle)
0043         return -ENOMEM;
0044 
0045     /* convert handle size to multiple of sizeof(u32) */
0046     handle_dwords = f_handle.handle_bytes >> 2;
0047 
0048     /* we ask for a non connected handle */
0049     retval = exportfs_encode_fh(path->dentry,
0050                     (struct fid *)handle->f_handle,
0051                     &handle_dwords,  0);
0052     handle->handle_type = retval;
0053     /* convert handle size to bytes */
0054     handle_bytes = handle_dwords * sizeof(u32);
0055     handle->handle_bytes = handle_bytes;
0056     if ((handle->handle_bytes > f_handle.handle_bytes) ||
0057         (retval == FILEID_INVALID) || (retval == -ENOSPC)) {
0058         /* As per old exportfs_encode_fh documentation
0059          * we could return ENOSPC to indicate overflow
0060          * But file system returned 255 always. So handle
0061          * both the values
0062          */
0063         /*
0064          * set the handle size to zero so we copy only
0065          * non variable part of the file_handle
0066          */
0067         handle_bytes = 0;
0068         retval = -EOVERFLOW;
0069     } else
0070         retval = 0;
0071     /* copy the mount id */
0072     if (put_user(real_mount(path->mnt)->mnt_id, mnt_id) ||
0073         copy_to_user(ufh, handle,
0074              sizeof(struct file_handle) + handle_bytes))
0075         retval = -EFAULT;
0076     kfree(handle);
0077     return retval;
0078 }
0079 
0080 /**
0081  * sys_name_to_handle_at: convert name to handle
0082  * @dfd: directory relative to which name is interpreted if not absolute
0083  * @name: name that should be converted to handle.
0084  * @handle: resulting file handle
0085  * @mnt_id: mount id of the file system containing the file
0086  * @flag: flag value to indicate whether to follow symlink or not
0087  *
0088  * @handle->handle_size indicate the space available to store the
0089  * variable part of the file handle in bytes. If there is not
0090  * enough space, the field is updated to return the minimum
0091  * value required.
0092  */
0093 SYSCALL_DEFINE5(name_to_handle_at, int, dfd, const char __user *, name,
0094         struct file_handle __user *, handle, int __user *, mnt_id,
0095         int, flag)
0096 {
0097     struct path path;
0098     int lookup_flags;
0099     int err;
0100 
0101     if ((flag & ~(AT_SYMLINK_FOLLOW | AT_EMPTY_PATH)) != 0)
0102         return -EINVAL;
0103 
0104     lookup_flags = (flag & AT_SYMLINK_FOLLOW) ? LOOKUP_FOLLOW : 0;
0105     if (flag & AT_EMPTY_PATH)
0106         lookup_flags |= LOOKUP_EMPTY;
0107     err = user_path_at(dfd, name, lookup_flags, &path);
0108     if (!err) {
0109         err = do_sys_name_to_handle(&path, handle, mnt_id);
0110         path_put(&path);
0111     }
0112     return err;
0113 }
0114 
0115 static struct vfsmount *get_vfsmount_from_fd(int fd)
0116 {
0117     struct vfsmount *mnt;
0118 
0119     if (fd == AT_FDCWD) {
0120         struct fs_struct *fs = current->fs;
0121         spin_lock(&fs->lock);
0122         mnt = mntget(fs->pwd.mnt);
0123         spin_unlock(&fs->lock);
0124     } else {
0125         struct fd f = fdget(fd);
0126         if (!f.file)
0127             return ERR_PTR(-EBADF);
0128         mnt = mntget(f.file->f_path.mnt);
0129         fdput(f);
0130     }
0131     return mnt;
0132 }
0133 
0134 static int vfs_dentry_acceptable(void *context, struct dentry *dentry)
0135 {
0136     return 1;
0137 }
0138 
0139 static int do_handle_to_path(int mountdirfd, struct file_handle *handle,
0140                  struct path *path)
0141 {
0142     int retval = 0;
0143     int handle_dwords;
0144 
0145     path->mnt = get_vfsmount_from_fd(mountdirfd);
0146     if (IS_ERR(path->mnt)) {
0147         retval = PTR_ERR(path->mnt);
0148         goto out_err;
0149     }
0150     /* change the handle size to multiple of sizeof(u32) */
0151     handle_dwords = handle->handle_bytes >> 2;
0152     path->dentry = exportfs_decode_fh(path->mnt,
0153                       (struct fid *)handle->f_handle,
0154                       handle_dwords, handle->handle_type,
0155                       vfs_dentry_acceptable, NULL);
0156     if (IS_ERR(path->dentry)) {
0157         retval = PTR_ERR(path->dentry);
0158         goto out_mnt;
0159     }
0160     return 0;
0161 out_mnt:
0162     mntput(path->mnt);
0163 out_err:
0164     return retval;
0165 }
0166 
0167 static int handle_to_path(int mountdirfd, struct file_handle __user *ufh,
0168            struct path *path)
0169 {
0170     int retval = 0;
0171     struct file_handle f_handle;
0172     struct file_handle *handle = NULL;
0173 
0174     /*
0175      * With handle we don't look at the execute bit on the
0176      * directory. Ideally we would like CAP_DAC_SEARCH.
0177      * But we don't have that
0178      */
0179     if (!capable(CAP_DAC_READ_SEARCH)) {
0180         retval = -EPERM;
0181         goto out_err;
0182     }
0183     if (copy_from_user(&f_handle, ufh, sizeof(struct file_handle))) {
0184         retval = -EFAULT;
0185         goto out_err;
0186     }
0187     if ((f_handle.handle_bytes > MAX_HANDLE_SZ) ||
0188         (f_handle.handle_bytes == 0)) {
0189         retval = -EINVAL;
0190         goto out_err;
0191     }
0192     handle = kmalloc(sizeof(struct file_handle) + f_handle.handle_bytes,
0193              GFP_KERNEL);
0194     if (!handle) {
0195         retval = -ENOMEM;
0196         goto out_err;
0197     }
0198     /* copy the full handle */
0199     *handle = f_handle;
0200     if (copy_from_user(&handle->f_handle,
0201                &ufh->f_handle,
0202                f_handle.handle_bytes)) {
0203         retval = -EFAULT;
0204         goto out_handle;
0205     }
0206 
0207     retval = do_handle_to_path(mountdirfd, handle, path);
0208 
0209 out_handle:
0210     kfree(handle);
0211 out_err:
0212     return retval;
0213 }
0214 
0215 static long do_handle_open(int mountdirfd, struct file_handle __user *ufh,
0216                int open_flag)
0217 {
0218     long retval = 0;
0219     struct path path;
0220     struct file *file;
0221     int fd;
0222 
0223     retval = handle_to_path(mountdirfd, ufh, &path);
0224     if (retval)
0225         return retval;
0226 
0227     fd = get_unused_fd_flags(open_flag);
0228     if (fd < 0) {
0229         path_put(&path);
0230         return fd;
0231     }
0232     file = file_open_root(&path, "", open_flag, 0);
0233     if (IS_ERR(file)) {
0234         put_unused_fd(fd);
0235         retval =  PTR_ERR(file);
0236     } else {
0237         retval = fd;
0238         fsnotify_open(file);
0239         fd_install(fd, file);
0240     }
0241     path_put(&path);
0242     return retval;
0243 }
0244 
0245 /**
0246  * sys_open_by_handle_at: Open the file handle
0247  * @mountdirfd: directory file descriptor
0248  * @handle: file handle to be opened
0249  * @flags: open flags.
0250  *
0251  * @mountdirfd indicate the directory file descriptor
0252  * of the mount point. file handle is decoded relative
0253  * to the vfsmount pointed by the @mountdirfd. @flags
0254  * value is same as the open(2) flags.
0255  */
0256 SYSCALL_DEFINE3(open_by_handle_at, int, mountdirfd,
0257         struct file_handle __user *, handle,
0258         int, flags)
0259 {
0260     long ret;
0261 
0262     if (force_o_largefile())
0263         flags |= O_LARGEFILE;
0264 
0265     ret = do_handle_open(mountdirfd, handle, flags);
0266     return ret;
0267 }
0268 
0269 #ifdef CONFIG_COMPAT
0270 /*
0271  * Exactly like fs/open.c:sys_open_by_handle_at(), except that it
0272  * doesn't set the O_LARGEFILE flag.
0273  */
0274 COMPAT_SYSCALL_DEFINE3(open_by_handle_at, int, mountdirfd,
0275                  struct file_handle __user *, handle, int, flags)
0276 {
0277     return do_handle_open(mountdirfd, handle, flags);
0278 }
0279 #endif