xref: /openbmc/linux/fs/fhandle.c (revision 1760371b277718062211fc7eb6f3042c5051c1a5)
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