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