1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
2990d6c2dSAneesh Kumar K.V #include <linux/syscalls.h>
3990d6c2dSAneesh Kumar K.V #include <linux/slab.h>
4990d6c2dSAneesh Kumar K.V #include <linux/fs.h>
5990d6c2dSAneesh Kumar K.V #include <linux/file.h>
6990d6c2dSAneesh Kumar K.V #include <linux/mount.h>
7990d6c2dSAneesh Kumar K.V #include <linux/namei.h>
8990d6c2dSAneesh Kumar K.V #include <linux/exportfs.h>
9becfd1f3SAneesh Kumar K.V #include <linux/fs_struct.h>
10becfd1f3SAneesh Kumar K.V #include <linux/fsnotify.h>
11ed5afeafSJeff Mahoney #include <linux/personality.h>
127c0f6ba6SLinus Torvalds #include <linux/uaccess.h>
132b891026SAl Viro #include <linux/compat.h>
14990d6c2dSAneesh Kumar K.V #include "internal.h"
1515169fe7SAl Viro #include "mount.h"
16990d6c2dSAneesh Kumar K.V
do_sys_name_to_handle(const struct path * path,struct file_handle __user * ufh,int __user * mnt_id,int fh_flags)176ccaaf59SAl Viro static long do_sys_name_to_handle(const struct path *path,
18990d6c2dSAneesh Kumar K.V struct file_handle __user *ufh,
1996b2b072SAmir Goldstein int __user *mnt_id, int fh_flags)
20990d6c2dSAneesh Kumar K.V {
21990d6c2dSAneesh Kumar K.V long retval;
22990d6c2dSAneesh Kumar K.V struct file_handle f_handle;
23990d6c2dSAneesh Kumar K.V int handle_dwords, handle_bytes;
24990d6c2dSAneesh Kumar K.V struct file_handle *handle = NULL;
25990d6c2dSAneesh Kumar K.V
26990d6c2dSAneesh Kumar K.V /*
2796b2b072SAmir Goldstein * We need to make sure whether the file system support decoding of
2896b2b072SAmir Goldstein * the file handle if decodeable file handle was requested.
2996b2b072SAmir Goldstein * Otherwise, even empty export_operations are sufficient to opt-in
3096b2b072SAmir Goldstein * to encoding FIDs.
31990d6c2dSAneesh Kumar K.V */
32d8c9584eSAl Viro if (!path->dentry->d_sb->s_export_op ||
3396b2b072SAmir Goldstein (!(fh_flags & EXPORT_FH_FID) &&
3496b2b072SAmir Goldstein !path->dentry->d_sb->s_export_op->fh_to_dentry))
35990d6c2dSAneesh Kumar K.V return -EOPNOTSUPP;
36990d6c2dSAneesh Kumar K.V
37990d6c2dSAneesh Kumar K.V if (copy_from_user(&f_handle, ufh, sizeof(struct file_handle)))
38990d6c2dSAneesh Kumar K.V return -EFAULT;
39990d6c2dSAneesh Kumar K.V
40990d6c2dSAneesh Kumar K.V if (f_handle.handle_bytes > MAX_HANDLE_SZ)
41990d6c2dSAneesh Kumar K.V return -EINVAL;
42990d6c2dSAneesh Kumar K.V
43*107449cfSGustavo A. R. Silva handle = kzalloc(struct_size(handle, f_handle, f_handle.handle_bytes),
44990d6c2dSAneesh Kumar K.V GFP_KERNEL);
45990d6c2dSAneesh Kumar K.V if (!handle)
46990d6c2dSAneesh Kumar K.V return -ENOMEM;
47990d6c2dSAneesh Kumar K.V
48990d6c2dSAneesh Kumar K.V /* convert handle size to multiple of sizeof(u32) */
49990d6c2dSAneesh Kumar K.V handle_dwords = f_handle.handle_bytes >> 2;
50990d6c2dSAneesh Kumar K.V
5196b2b072SAmir Goldstein /* we ask for a non connectable maybe decodeable file handle */
52990d6c2dSAneesh Kumar K.V retval = exportfs_encode_fh(path->dentry,
53990d6c2dSAneesh Kumar K.V (struct fid *)handle->f_handle,
5496b2b072SAmir Goldstein &handle_dwords, fh_flags);
55990d6c2dSAneesh Kumar K.V handle->handle_type = retval;
56990d6c2dSAneesh Kumar K.V /* convert handle size to bytes */
57990d6c2dSAneesh Kumar K.V handle_bytes = handle_dwords * sizeof(u32);
58990d6c2dSAneesh Kumar K.V handle->handle_bytes = handle_bytes;
59990d6c2dSAneesh Kumar K.V if ((handle->handle_bytes > f_handle.handle_bytes) ||
607cdafe6cSAmir Goldstein (retval == FILEID_INVALID) || (retval < 0)) {
61990d6c2dSAneesh Kumar K.V /* As per old exportfs_encode_fh documentation
62990d6c2dSAneesh Kumar K.V * we could return ENOSPC to indicate overflow
63990d6c2dSAneesh Kumar K.V * But file system returned 255 always. So handle
64990d6c2dSAneesh Kumar K.V * both the values
65990d6c2dSAneesh Kumar K.V */
667cdafe6cSAmir Goldstein if (retval == FILEID_INVALID || retval == -ENOSPC)
677cdafe6cSAmir Goldstein retval = -EOVERFLOW;
68990d6c2dSAneesh Kumar K.V /*
69990d6c2dSAneesh Kumar K.V * set the handle size to zero so we copy only
70990d6c2dSAneesh Kumar K.V * non variable part of the file_handle
71990d6c2dSAneesh Kumar K.V */
72990d6c2dSAneesh Kumar K.V handle_bytes = 0;
73990d6c2dSAneesh Kumar K.V } else
74990d6c2dSAneesh Kumar K.V retval = 0;
75990d6c2dSAneesh Kumar K.V /* copy the mount id */
766391af6fSDavid Windsor if (put_user(real_mount(path->mnt)->mnt_id, mnt_id) ||
77990d6c2dSAneesh Kumar K.V copy_to_user(ufh, handle,
78*107449cfSGustavo A. R. Silva struct_size(handle, f_handle, handle_bytes)))
79990d6c2dSAneesh Kumar K.V retval = -EFAULT;
80990d6c2dSAneesh Kumar K.V kfree(handle);
81990d6c2dSAneesh Kumar K.V return retval;
82990d6c2dSAneesh Kumar K.V }
83990d6c2dSAneesh Kumar K.V
84990d6c2dSAneesh Kumar K.V /**
85990d6c2dSAneesh Kumar K.V * sys_name_to_handle_at: convert name to handle
86990d6c2dSAneesh Kumar K.V * @dfd: directory relative to which name is interpreted if not absolute
87990d6c2dSAneesh Kumar K.V * @name: name that should be converted to handle.
88990d6c2dSAneesh Kumar K.V * @handle: resulting file handle
89990d6c2dSAneesh Kumar K.V * @mnt_id: mount id of the file system containing the file
90990d6c2dSAneesh Kumar K.V * @flag: flag value to indicate whether to follow symlink or not
9196b2b072SAmir Goldstein * and whether a decodable file handle is required.
92990d6c2dSAneesh Kumar K.V *
93990d6c2dSAneesh Kumar K.V * @handle->handle_size indicate the space available to store the
94990d6c2dSAneesh Kumar K.V * variable part of the file handle in bytes. If there is not
95990d6c2dSAneesh Kumar K.V * enough space, the field is updated to return the minimum
96990d6c2dSAneesh Kumar K.V * value required.
97990d6c2dSAneesh Kumar K.V */
SYSCALL_DEFINE5(name_to_handle_at,int,dfd,const char __user *,name,struct file_handle __user *,handle,int __user *,mnt_id,int,flag)98990d6c2dSAneesh Kumar K.V SYSCALL_DEFINE5(name_to_handle_at, int, dfd, const char __user *, name,
99990d6c2dSAneesh Kumar K.V struct file_handle __user *, handle, int __user *, mnt_id,
100990d6c2dSAneesh Kumar K.V int, flag)
101990d6c2dSAneesh Kumar K.V {
102990d6c2dSAneesh Kumar K.V struct path path;
103990d6c2dSAneesh Kumar K.V int lookup_flags;
10496b2b072SAmir Goldstein int fh_flags;
105990d6c2dSAneesh Kumar K.V int err;
106990d6c2dSAneesh Kumar K.V
10796b2b072SAmir Goldstein if (flag & ~(AT_SYMLINK_FOLLOW | AT_EMPTY_PATH | AT_HANDLE_FID))
108990d6c2dSAneesh Kumar K.V return -EINVAL;
109990d6c2dSAneesh Kumar K.V
110990d6c2dSAneesh Kumar K.V lookup_flags = (flag & AT_SYMLINK_FOLLOW) ? LOOKUP_FOLLOW : 0;
11196b2b072SAmir Goldstein fh_flags = (flag & AT_HANDLE_FID) ? EXPORT_FH_FID : 0;
112990d6c2dSAneesh Kumar K.V if (flag & AT_EMPTY_PATH)
113990d6c2dSAneesh Kumar K.V lookup_flags |= LOOKUP_EMPTY;
114990d6c2dSAneesh Kumar K.V err = user_path_at(dfd, name, lookup_flags, &path);
115990d6c2dSAneesh Kumar K.V if (!err) {
11696b2b072SAmir Goldstein err = do_sys_name_to_handle(&path, handle, mnt_id, fh_flags);
117990d6c2dSAneesh Kumar K.V path_put(&path);
118990d6c2dSAneesh Kumar K.V }
119990d6c2dSAneesh Kumar K.V return err;
120990d6c2dSAneesh Kumar K.V }
121becfd1f3SAneesh Kumar K.V
get_vfsmount_from_fd(int fd)122becfd1f3SAneesh Kumar K.V static struct vfsmount *get_vfsmount_from_fd(int fd)
123becfd1f3SAneesh Kumar K.V {
1242903ff01SAl Viro struct vfsmount *mnt;
125becfd1f3SAneesh Kumar K.V
126becfd1f3SAneesh Kumar K.V if (fd == AT_FDCWD) {
127becfd1f3SAneesh Kumar K.V struct fs_struct *fs = current->fs;
128becfd1f3SAneesh Kumar K.V spin_lock(&fs->lock);
1292903ff01SAl Viro mnt = mntget(fs->pwd.mnt);
130becfd1f3SAneesh Kumar K.V spin_unlock(&fs->lock);
131becfd1f3SAneesh Kumar K.V } else {
1322903ff01SAl Viro struct fd f = fdget(fd);
1332903ff01SAl Viro if (!f.file)
134becfd1f3SAneesh Kumar K.V return ERR_PTR(-EBADF);
1352903ff01SAl Viro mnt = mntget(f.file->f_path.mnt);
1362903ff01SAl Viro fdput(f);
137becfd1f3SAneesh Kumar K.V }
1382903ff01SAl Viro return mnt;
139becfd1f3SAneesh Kumar K.V }
140becfd1f3SAneesh Kumar K.V
vfs_dentry_acceptable(void * context,struct dentry * dentry)141becfd1f3SAneesh Kumar K.V static int vfs_dentry_acceptable(void *context, struct dentry *dentry)
142becfd1f3SAneesh Kumar K.V {
143becfd1f3SAneesh Kumar K.V return 1;
144becfd1f3SAneesh Kumar K.V }
145becfd1f3SAneesh Kumar K.V
do_handle_to_path(int mountdirfd,struct file_handle * handle,struct path * path)146becfd1f3SAneesh Kumar K.V static int do_handle_to_path(int mountdirfd, struct file_handle *handle,
147becfd1f3SAneesh Kumar K.V struct path *path)
148becfd1f3SAneesh Kumar K.V {
149becfd1f3SAneesh Kumar K.V int retval = 0;
150becfd1f3SAneesh Kumar K.V int handle_dwords;
151becfd1f3SAneesh Kumar K.V
152becfd1f3SAneesh Kumar K.V path->mnt = get_vfsmount_from_fd(mountdirfd);
153becfd1f3SAneesh Kumar K.V if (IS_ERR(path->mnt)) {
154becfd1f3SAneesh Kumar K.V retval = PTR_ERR(path->mnt);
155becfd1f3SAneesh Kumar K.V goto out_err;
156becfd1f3SAneesh Kumar K.V }
157becfd1f3SAneesh Kumar K.V /* change the handle size to multiple of sizeof(u32) */
158becfd1f3SAneesh Kumar K.V handle_dwords = handle->handle_bytes >> 2;
159becfd1f3SAneesh Kumar K.V path->dentry = exportfs_decode_fh(path->mnt,
160becfd1f3SAneesh Kumar K.V (struct fid *)handle->f_handle,
161becfd1f3SAneesh Kumar K.V handle_dwords, handle->handle_type,
162becfd1f3SAneesh Kumar K.V vfs_dentry_acceptable, NULL);
163becfd1f3SAneesh Kumar K.V if (IS_ERR(path->dentry)) {
164becfd1f3SAneesh Kumar K.V retval = PTR_ERR(path->dentry);
165becfd1f3SAneesh Kumar K.V goto out_mnt;
166becfd1f3SAneesh Kumar K.V }
167becfd1f3SAneesh Kumar K.V return 0;
168becfd1f3SAneesh Kumar K.V out_mnt:
169becfd1f3SAneesh Kumar K.V mntput(path->mnt);
170becfd1f3SAneesh Kumar K.V out_err:
171becfd1f3SAneesh Kumar K.V return retval;
172becfd1f3SAneesh Kumar K.V }
173becfd1f3SAneesh Kumar K.V
handle_to_path(int mountdirfd,struct file_handle __user * ufh,struct path * path)174becfd1f3SAneesh Kumar K.V static int handle_to_path(int mountdirfd, struct file_handle __user *ufh,
175becfd1f3SAneesh Kumar K.V struct path *path)
176becfd1f3SAneesh Kumar K.V {
177becfd1f3SAneesh Kumar K.V int retval = 0;
178becfd1f3SAneesh Kumar K.V struct file_handle f_handle;
179becfd1f3SAneesh Kumar K.V struct file_handle *handle = NULL;
180becfd1f3SAneesh Kumar K.V
181becfd1f3SAneesh Kumar K.V /*
182becfd1f3SAneesh Kumar K.V * With handle we don't look at the execute bit on the
1833d742d4bSRandy Dunlap * directory. Ideally we would like CAP_DAC_SEARCH.
184becfd1f3SAneesh Kumar K.V * But we don't have that
185becfd1f3SAneesh Kumar K.V */
186becfd1f3SAneesh Kumar K.V if (!capable(CAP_DAC_READ_SEARCH)) {
187becfd1f3SAneesh Kumar K.V retval = -EPERM;
188becfd1f3SAneesh Kumar K.V goto out_err;
189becfd1f3SAneesh Kumar K.V }
190becfd1f3SAneesh Kumar K.V if (copy_from_user(&f_handle, ufh, sizeof(struct file_handle))) {
191becfd1f3SAneesh Kumar K.V retval = -EFAULT;
192becfd1f3SAneesh Kumar K.V goto out_err;
193becfd1f3SAneesh Kumar K.V }
194becfd1f3SAneesh Kumar K.V if ((f_handle.handle_bytes > MAX_HANDLE_SZ) ||
195becfd1f3SAneesh Kumar K.V (f_handle.handle_bytes == 0)) {
196becfd1f3SAneesh Kumar K.V retval = -EINVAL;
197becfd1f3SAneesh Kumar K.V goto out_err;
198becfd1f3SAneesh Kumar K.V }
199*107449cfSGustavo A. R. Silva handle = kmalloc(struct_size(handle, f_handle, f_handle.handle_bytes),
200becfd1f3SAneesh Kumar K.V GFP_KERNEL);
201becfd1f3SAneesh Kumar K.V if (!handle) {
202becfd1f3SAneesh Kumar K.V retval = -ENOMEM;
203becfd1f3SAneesh Kumar K.V goto out_err;
204becfd1f3SAneesh Kumar K.V }
205becfd1f3SAneesh Kumar K.V /* copy the full handle */
206161f873bSSasha Levin *handle = f_handle;
207161f873bSSasha Levin if (copy_from_user(&handle->f_handle,
208161f873bSSasha Levin &ufh->f_handle,
209becfd1f3SAneesh Kumar K.V f_handle.handle_bytes)) {
210becfd1f3SAneesh Kumar K.V retval = -EFAULT;
211becfd1f3SAneesh Kumar K.V goto out_handle;
212becfd1f3SAneesh Kumar K.V }
213becfd1f3SAneesh Kumar K.V
214becfd1f3SAneesh Kumar K.V retval = do_handle_to_path(mountdirfd, handle, path);
215becfd1f3SAneesh Kumar K.V
216becfd1f3SAneesh Kumar K.V out_handle:
217becfd1f3SAneesh Kumar K.V kfree(handle);
218becfd1f3SAneesh Kumar K.V out_err:
219becfd1f3SAneesh Kumar K.V return retval;
220becfd1f3SAneesh Kumar K.V }
221becfd1f3SAneesh Kumar K.V
do_handle_open(int mountdirfd,struct file_handle __user * ufh,int open_flag)22273ecf5cfSAl Viro static long do_handle_open(int mountdirfd, struct file_handle __user *ufh,
22373ecf5cfSAl Viro int open_flag)
224becfd1f3SAneesh Kumar K.V {
225becfd1f3SAneesh Kumar K.V long retval = 0;
226becfd1f3SAneesh Kumar K.V struct path path;
227becfd1f3SAneesh Kumar K.V struct file *file;
228becfd1f3SAneesh Kumar K.V int fd;
229becfd1f3SAneesh Kumar K.V
230becfd1f3SAneesh Kumar K.V retval = handle_to_path(mountdirfd, ufh, &path);
231becfd1f3SAneesh Kumar K.V if (retval)
232becfd1f3SAneesh Kumar K.V return retval;
233becfd1f3SAneesh Kumar K.V
234becfd1f3SAneesh Kumar K.V fd = get_unused_fd_flags(open_flag);
235becfd1f3SAneesh Kumar K.V if (fd < 0) {
236becfd1f3SAneesh Kumar K.V path_put(&path);
237becfd1f3SAneesh Kumar K.V return fd;
238becfd1f3SAneesh Kumar K.V }
239ffb37ca3SAl Viro file = file_open_root(&path, "", open_flag, 0);
240becfd1f3SAneesh Kumar K.V if (IS_ERR(file)) {
241becfd1f3SAneesh Kumar K.V put_unused_fd(fd);
242becfd1f3SAneesh Kumar K.V retval = PTR_ERR(file);
243becfd1f3SAneesh Kumar K.V } else {
244becfd1f3SAneesh Kumar K.V retval = fd;
245becfd1f3SAneesh Kumar K.V fd_install(fd, file);
246becfd1f3SAneesh Kumar K.V }
247becfd1f3SAneesh Kumar K.V path_put(&path);
248becfd1f3SAneesh Kumar K.V return retval;
249becfd1f3SAneesh Kumar K.V }
250becfd1f3SAneesh Kumar K.V
251becfd1f3SAneesh Kumar K.V /**
252becfd1f3SAneesh Kumar K.V * sys_open_by_handle_at: Open the file handle
253becfd1f3SAneesh Kumar K.V * @mountdirfd: directory file descriptor
254becfd1f3SAneesh Kumar K.V * @handle: file handle to be opened
255a92c7ba9SValdis Klētnieks * @flags: open flags.
256becfd1f3SAneesh Kumar K.V *
257becfd1f3SAneesh Kumar K.V * @mountdirfd indicate the directory file descriptor
258becfd1f3SAneesh Kumar K.V * of the mount point. file handle is decoded relative
259becfd1f3SAneesh Kumar K.V * to the vfsmount pointed by the @mountdirfd. @flags
260becfd1f3SAneesh Kumar K.V * value is same as the open(2) flags.
261becfd1f3SAneesh Kumar K.V */
SYSCALL_DEFINE3(open_by_handle_at,int,mountdirfd,struct file_handle __user *,handle,int,flags)262becfd1f3SAneesh Kumar K.V SYSCALL_DEFINE3(open_by_handle_at, int, mountdirfd,
263becfd1f3SAneesh Kumar K.V struct file_handle __user *, handle,
264becfd1f3SAneesh Kumar K.V int, flags)
265becfd1f3SAneesh Kumar K.V {
266becfd1f3SAneesh Kumar K.V long ret;
267becfd1f3SAneesh Kumar K.V
268becfd1f3SAneesh Kumar K.V if (force_o_largefile())
269becfd1f3SAneesh Kumar K.V flags |= O_LARGEFILE;
270becfd1f3SAneesh Kumar K.V
271becfd1f3SAneesh Kumar K.V ret = do_handle_open(mountdirfd, handle, flags);
272becfd1f3SAneesh Kumar K.V return ret;
273becfd1f3SAneesh Kumar K.V }
2742b891026SAl Viro
2752b891026SAl Viro #ifdef CONFIG_COMPAT
2762b891026SAl Viro /*
2772b891026SAl Viro * Exactly like fs/open.c:sys_open_by_handle_at(), except that it
2782b891026SAl Viro * doesn't set the O_LARGEFILE flag.
2792b891026SAl Viro */
COMPAT_SYSCALL_DEFINE3(open_by_handle_at,int,mountdirfd,struct file_handle __user *,handle,int,flags)2802b891026SAl Viro COMPAT_SYSCALL_DEFINE3(open_by_handle_at, int, mountdirfd,
2812b891026SAl Viro struct file_handle __user *, handle, int, flags)
2822b891026SAl Viro {
2832b891026SAl Viro return do_handle_open(mountdirfd, handle, flags);
2842b891026SAl Viro }
2852b891026SAl Viro #endif
286