Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

exportfs: allow exporting non-decodeable file handles to userspace

Some userspace programs use st_ino as a unique object identifier, even
though inode numbers may be recycable.

This issue has been addressed for NFS export long ago using the exportfs
file handle API and the unique file handle identifiers are also exported
to userspace via name_to_handle_at(2).

fanotify also uses file handles to identify objects in events, but only
for filesystems that support NFS export.

Relax the requirement for NFS export support and allow more filesystems
to export a unique object identifier via name_to_handle_at(2) with the
flag AT_HANDLE_FID.

A file handle requested with the AT_HANDLE_FID flag, may or may not be
usable as an argument to open_by_handle_at(2).

To allow filesystems to opt-in to supporting AT_HANDLE_FID, a struct
export_operations is required, but even an empty struct is sufficient
for encoding FIDs.

Acked-by: Jeff Layton <jlayton@kernel.org>
Acked-by: Chuck Lever <chuck.lever@oracle.com>
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
Acked-by: Christian Brauner <brauner@kernel.org>
Signed-off-by: Jan Kara <jack@suse.cz>
Message-Id: <20230502124817.3070545-4-amir73il@gmail.com>

authored by

Amir Goldstein and committed by
Jan Kara
96b2b072 304e9c83

+19 -8
+14 -8
fs/fhandle.c
··· 16 16 17 17 static long do_sys_name_to_handle(const struct path *path, 18 18 struct file_handle __user *ufh, 19 - int __user *mnt_id) 19 + int __user *mnt_id, int fh_flags) 20 20 { 21 21 long retval; 22 22 struct file_handle f_handle; ··· 24 24 struct file_handle *handle = NULL; 25 25 26 26 /* 27 - * We need to make sure whether the file system 28 - * support decoding of the file handle 27 + * We need to make sure whether the file system support decoding of 28 + * the file handle if decodeable file handle was requested. 29 + * Otherwise, even empty export_operations are sufficient to opt-in 30 + * to encoding FIDs. 29 31 */ 30 32 if (!path->dentry->d_sb->s_export_op || 31 - !path->dentry->d_sb->s_export_op->fh_to_dentry) 33 + (!(fh_flags & EXPORT_FH_FID) && 34 + !path->dentry->d_sb->s_export_op->fh_to_dentry)) 32 35 return -EOPNOTSUPP; 33 36 34 37 if (copy_from_user(&f_handle, ufh, sizeof(struct file_handle))) ··· 48 45 /* convert handle size to multiple of sizeof(u32) */ 49 46 handle_dwords = f_handle.handle_bytes >> 2; 50 47 51 - /* we ask for a non connected handle */ 48 + /* we ask for a non connectable maybe decodeable file handle */ 52 49 retval = exportfs_encode_fh(path->dentry, 53 50 (struct fid *)handle->f_handle, 54 - &handle_dwords, 0); 51 + &handle_dwords, fh_flags); 55 52 handle->handle_type = retval; 56 53 /* convert handle size to bytes */ 57 54 handle_bytes = handle_dwords * sizeof(u32); ··· 87 84 * @handle: resulting file handle 88 85 * @mnt_id: mount id of the file system containing the file 89 86 * @flag: flag value to indicate whether to follow symlink or not 87 + * and whether a decodable file handle is required. 90 88 * 91 89 * @handle->handle_size indicate the space available to store the 92 90 * variable part of the file handle in bytes. If there is not ··· 100 96 { 101 97 struct path path; 102 98 int lookup_flags; 99 + int fh_flags; 103 100 int err; 104 101 105 - if ((flag & ~(AT_SYMLINK_FOLLOW | AT_EMPTY_PATH)) != 0) 102 + if (flag & ~(AT_SYMLINK_FOLLOW | AT_EMPTY_PATH | AT_HANDLE_FID)) 106 103 return -EINVAL; 107 104 108 105 lookup_flags = (flag & AT_SYMLINK_FOLLOW) ? LOOKUP_FOLLOW : 0; 106 + fh_flags = (flag & AT_HANDLE_FID) ? EXPORT_FH_FID : 0; 109 107 if (flag & AT_EMPTY_PATH) 110 108 lookup_flags |= LOOKUP_EMPTY; 111 109 err = user_path_at(dfd, name, lookup_flags, &path); 112 110 if (!err) { 113 - err = do_sys_name_to_handle(&path, handle, mnt_id); 111 + err = do_sys_name_to_handle(&path, handle, mnt_id, fh_flags); 114 112 path_put(&path); 115 113 } 116 114 return err;
+5
include/uapi/linux/fcntl.h
··· 112 112 113 113 #define AT_RECURSIVE 0x8000 /* Apply to the entire subtree */ 114 114 115 + /* Flags for name_to_handle_at(2). We reuse AT_ flag space to save bits... */ 116 + #define AT_HANDLE_FID AT_REMOVEDIR /* file handle is needed to 117 + compare object identity and may not 118 + be usable to open_by_handle_at(2) */ 119 + 115 120 #endif /* _UAPI_LINUX_FCNTL_H */