* [PATCH v3 0/3] API for exporting connectable file handles to userspace
@ 2024-10-08 15:21 Amir Goldstein
2024-10-08 15:21 ` [PATCH v3 1/3] fs: prepare for "explicit connectable" file handles Amir Goldstein
` (3 more replies)
0 siblings, 4 replies; 12+ messages in thread
From: Amir Goldstein @ 2024-10-08 15:21 UTC (permalink / raw)
To: Jeff Layton
Cc: Christian Brauner, Jan Kara, Aleksa Sarai, Chuck Lever,
linux-fsdevel, linux-nfs
Jeff,
These patches bring the NFS connectable file handles feature to
userspace servers.
They rely on Christian's and Aleksa's changes recently merged to v6.12.
The API I chose for encoding conenctable file handles is pretty
conventional (AT_HANDLE_CONNECTABLE).
open_by_handle_at(2) does not have AT_ flags argument, but also, I find
it more useful API that encoding a connectable file handle can mandate
the resolving of a connected fd, without having to opt-in for a
connected fd independently.
I chose to implemnent this by using upper bits in the handle type field
It may be valid (?) for filesystems to return a handle type with upper
bits set, but AFAIK, no in-tree filesystem does that.
I added some assertions just in case.
Thanks,
Amir.
Changes since v2 [2]:
- Use bit arithmetics instead of bitfileds (Jeff)
- Add assertions about use of high type bits
Changes since v1 [1]:
- Assert on encode for disconnected path (Jeff)
- Don't allow AT_HANDLE_CONNECTABLE with AT_EMPTY_PATH
- Drop the O_PATH mount_fd API hack (Jeff)
- Encode an explicit "connectable" flag in handle type
[1] https://lore.kernel.org/linux-fsdevel/20240919140611.1771651-1-amir73il@gmail.com/
[2] https://lore.kernel.org/linux-fsdevel/20240923082829.1910210-1-amir73il@gmail.com/
Amir Goldstein (3):
fs: prepare for "explicit connectable" file handles
fs: name_to_handle_at() support for "explicit connectable" file
handles
fs: open_by_handle_at() support for decoding "explicit connectable"
file handles
fs/exportfs/expfs.c | 14 ++++++--
fs/fhandle.c | 74 ++++++++++++++++++++++++++++++++++----
include/linux/exportfs.h | 16 +++++++++
include/uapi/linux/fcntl.h | 1 +
4 files changed, 97 insertions(+), 8 deletions(-)
--
2.34.1
^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH v3 1/3] fs: prepare for "explicit connectable" file handles
2024-10-08 15:21 [PATCH v3 0/3] API for exporting connectable file handles to userspace Amir Goldstein
@ 2024-10-08 15:21 ` Amir Goldstein
2024-10-08 18:19 ` Jeff Layton
2024-10-08 15:21 ` [PATCH v3 2/3] fs: name_to_handle_at() support " Amir Goldstein
` (2 subsequent siblings)
3 siblings, 1 reply; 12+ messages in thread
From: Amir Goldstein @ 2024-10-08 15:21 UTC (permalink / raw)
To: Jeff Layton
Cc: Christian Brauner, Jan Kara, Aleksa Sarai, Chuck Lever,
linux-fsdevel, linux-nfs
We would like to use the high 16bit of the handle_type field to encode
file handle traits, such as "connectable".
In preparation for this change, make sure that filesystems do not return
a handle_type value with upper bits set and that the open_by_handle_at(2)
syscall rejects these handle types.
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
---
fs/exportfs/expfs.c | 14 ++++++++++++--
fs/fhandle.c | 6 ++++++
include/linux/exportfs.h | 14 ++++++++++++++
3 files changed, 32 insertions(+), 2 deletions(-)
diff --git a/fs/exportfs/expfs.c b/fs/exportfs/expfs.c
index 4f2dd4ab4486..c8eb660fdde4 100644
--- a/fs/exportfs/expfs.c
+++ b/fs/exportfs/expfs.c
@@ -382,14 +382,21 @@ int exportfs_encode_inode_fh(struct inode *inode, struct fid *fid,
int *max_len, struct inode *parent, int flags)
{
const struct export_operations *nop = inode->i_sb->s_export_op;
+ enum fid_type type;
if (!exportfs_can_encode_fh(nop, flags))
return -EOPNOTSUPP;
if (!nop && (flags & EXPORT_FH_FID))
- return exportfs_encode_ino64_fid(inode, fid, max_len);
+ type = exportfs_encode_ino64_fid(inode, fid, max_len);
+ else
+ type = nop->encode_fh(inode, fid->raw, max_len, parent);
+
+ if (WARN_ON_ONCE(FILEID_USER_FLAGS(type)))
+ return -EINVAL;
+
+ return type;
- return nop->encode_fh(inode, fid->raw, max_len, parent);
}
EXPORT_SYMBOL_GPL(exportfs_encode_inode_fh);
@@ -436,6 +443,9 @@ exportfs_decode_fh_raw(struct vfsmount *mnt, struct fid *fid, int fh_len,
char nbuf[NAME_MAX+1];
int err;
+ if (WARN_ON_ONCE(FILEID_USER_FLAGS(fileid_type)))
+ return -EINVAL;
+
/*
* Try to get any dentry for the given file handle from the filesystem.
*/
diff --git a/fs/fhandle.c b/fs/fhandle.c
index 82df28d45cd7..c5792cf3c6e9 100644
--- a/fs/fhandle.c
+++ b/fs/fhandle.c
@@ -307,6 +307,10 @@ static int handle_to_path(int mountdirfd, struct file_handle __user *ufh,
retval = -EINVAL;
goto out_path;
}
+ if (!FILEID_USER_TYPE_IS_VALID(f_handle.handle_type)) {
+ retval = -EINVAL;
+ goto out_path;
+ }
handle = kmalloc(struct_size(handle, f_handle, f_handle.handle_bytes),
GFP_KERNEL);
if (!handle) {
@@ -322,6 +326,8 @@ static int handle_to_path(int mountdirfd, struct file_handle __user *ufh,
goto out_handle;
}
+ /* Filesystem code should not be exposed to user flags */
+ handle->handle_type &= ~FILEID_USER_FLAGS_MASK;
retval = do_handle_to_path(handle, path, &ctx);
out_handle:
diff --git a/include/linux/exportfs.h b/include/linux/exportfs.h
index 893a1d21dc1c..76a3050b3593 100644
--- a/include/linux/exportfs.h
+++ b/include/linux/exportfs.h
@@ -160,6 +160,20 @@ struct fid {
#define EXPORT_FH_FID 0x2 /* File handle may be non-decodeable */
#define EXPORT_FH_DIR_ONLY 0x4 /* Only decode file handle for a directory */
+/*
+ * Filesystems use only lower 8 bits of file_handle type for fid_type.
+ * name_to_handle_at() uses upper 16 bits of type as user flags to be
+ * interpreted by open_by_handle_at().
+ */
+#define FILEID_USER_FLAGS_MASK 0xffff0000
+#define FILEID_USER_FLAGS(type) ((type) & FILEID_USER_FLAGS_MASK)
+
+/* Flags supported in encoded handle_type that is exported to user */
+#define FILEID_VALID_USER_FLAGS (0)
+
+#define FILEID_USER_TYPE_IS_VALID(type) \
+ (!(FILEID_USER_FLAGS(type) & ~FILEID_VALID_USER_FLAGS))
+
/**
* struct export_operations - for nfsd to communicate with file systems
* @encode_fh: encode a file handle fragment from a dentry
--
2.34.1
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH v3 2/3] fs: name_to_handle_at() support for "explicit connectable" file handles
2024-10-08 15:21 [PATCH v3 0/3] API for exporting connectable file handles to userspace Amir Goldstein
2024-10-08 15:21 ` [PATCH v3 1/3] fs: prepare for "explicit connectable" file handles Amir Goldstein
@ 2024-10-08 15:21 ` Amir Goldstein
2024-10-08 18:31 ` Jeff Layton
2024-10-08 15:21 ` [PATCH v3 3/3] fs: open_by_handle_at() support for decoding " Amir Goldstein
2024-10-09 7:17 ` [PATCH v3 0/3] API for exporting connectable file handles to userspace Amir Goldstein
3 siblings, 1 reply; 12+ messages in thread
From: Amir Goldstein @ 2024-10-08 15:21 UTC (permalink / raw)
To: Jeff Layton
Cc: Christian Brauner, Jan Kara, Aleksa Sarai, Chuck Lever,
linux-fsdevel, linux-nfs
nfsd encodes "connectable" file handles for the subtree_check feature,
which can be resolved to an open file with a connected path.
So far, userspace nfs server could not make use of this functionality.
Introduce a new flag AT_HANDLE_CONNECTABLE to name_to_handle_at(2).
When used, the encoded file handle is "explicitly connectable".
The "explicitly connectable" file handle sets bits in the high 16bit of
the handle_type field, so open_by_handle_at(2) will know that it needs
to open a file with a connected path.
old kernels will now recognize the handle_type with high bits set,
so "explicitly connectable" file handles cannot be decoded by
open_by_handle_at(2) on old kernels.
The flag AT_HANDLE_CONNECTABLE is not allowed together with either
AT_HANDLE_FID or AT_EMPTY_PATH.
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
---
fs/fhandle.c | 48 ++++++++++++++++++++++++++++++++++----
include/linux/exportfs.h | 2 ++
include/uapi/linux/fcntl.h | 1 +
3 files changed, 46 insertions(+), 5 deletions(-)
diff --git a/fs/fhandle.c b/fs/fhandle.c
index c5792cf3c6e9..7b4c8945efcb 100644
--- a/fs/fhandle.c
+++ b/fs/fhandle.c
@@ -31,6 +31,14 @@ static long do_sys_name_to_handle(const struct path *path,
if (!exportfs_can_encode_fh(path->dentry->d_sb->s_export_op, fh_flags))
return -EOPNOTSUPP;
+ /*
+ * A request to encode a connectable handle for a disconnected dentry
+ * is unexpected since AT_EMPTY_PATH is not allowed.
+ */
+ if (fh_flags & EXPORT_FH_CONNECTABLE &&
+ WARN_ON(path->dentry->d_flags & DCACHE_DISCONNECTED))
+ return -EINVAL;
+
if (copy_from_user(&f_handle, ufh, sizeof(struct file_handle)))
return -EFAULT;
@@ -45,7 +53,7 @@ static long do_sys_name_to_handle(const struct path *path,
/* convert handle size to multiple of sizeof(u32) */
handle_dwords = f_handle.handle_bytes >> 2;
- /* we ask for a non connectable maybe decodeable file handle */
+ /* Encode a possibly decodeable/connectable file handle */
retval = exportfs_encode_fh(path->dentry,
(struct fid *)handle->f_handle,
&handle_dwords, fh_flags);
@@ -67,8 +75,23 @@ static long do_sys_name_to_handle(const struct path *path,
* non variable part of the file_handle
*/
handle_bytes = 0;
- } else
+ } else {
+ /*
+ * When asked to encode a connectable file handle, encode this
+ * property in the file handle itself, so that we later know
+ * how to decode it.
+ * For sanity, also encode in the file handle if the encoded
+ * object is a directory and verify this during decode, because
+ * decoding directory file handles is quite different than
+ * decoding connectable non-directory file handles.
+ */
+ if (fh_flags & EXPORT_FH_CONNECTABLE) {
+ handle->handle_type |= FILEID_IS_CONNECTABLE;
+ if (d_is_dir(path->dentry))
+ fh_flags |= FILEID_IS_DIR;
+ }
retval = 0;
+ }
/* copy the mount id */
if (unique_mntid) {
if (put_user(real_mount(path->mnt)->mnt_id_unique,
@@ -109,15 +132,30 @@ SYSCALL_DEFINE5(name_to_handle_at, int, dfd, const char __user *, name,
{
struct path path;
int lookup_flags;
- int fh_flags;
+ int fh_flags = 0;
int err;
if (flag & ~(AT_SYMLINK_FOLLOW | AT_EMPTY_PATH | AT_HANDLE_FID |
- AT_HANDLE_MNT_ID_UNIQUE))
+ AT_HANDLE_MNT_ID_UNIQUE | AT_HANDLE_CONNECTABLE))
+ return -EINVAL;
+
+ /*
+ * AT_HANDLE_FID means there is no intention to decode file handle
+ * AT_HANDLE_CONNECTABLE means there is an intention to decode a
+ * connected fd (with known path), so these flags are conflicting.
+ * AT_EMPTY_PATH could be used along with a dfd that refers to a
+ * disconnected non-directory, which cannot be used to encode a
+ * connectable file handle, because its parent is unknown.
+ */
+ if (flag & AT_HANDLE_CONNECTABLE &&
+ flag & (AT_HANDLE_FID | AT_EMPTY_PATH))
return -EINVAL;
+ else if (flag & AT_HANDLE_FID)
+ fh_flags |= EXPORT_FH_FID;
+ else if (flag & AT_HANDLE_CONNECTABLE)
+ fh_flags |= EXPORT_FH_CONNECTABLE;
lookup_flags = (flag & AT_SYMLINK_FOLLOW) ? LOOKUP_FOLLOW : 0;
- fh_flags = (flag & AT_HANDLE_FID) ? EXPORT_FH_FID : 0;
if (flag & AT_EMPTY_PATH)
lookup_flags |= LOOKUP_EMPTY;
err = user_path_at(dfd, name, lookup_flags, &path);
diff --git a/include/linux/exportfs.h b/include/linux/exportfs.h
index 76a3050b3593..230b0e1d669d 100644
--- a/include/linux/exportfs.h
+++ b/include/linux/exportfs.h
@@ -169,6 +169,8 @@ struct fid {
#define FILEID_USER_FLAGS(type) ((type) & FILEID_USER_FLAGS_MASK)
/* Flags supported in encoded handle_type that is exported to user */
+#define FILEID_IS_CONNECTABLE 0x10000
+#define FILEID_IS_DIR 0x40000
#define FILEID_VALID_USER_FLAGS (0)
#define FILEID_USER_TYPE_IS_VALID(type) \
diff --git a/include/uapi/linux/fcntl.h b/include/uapi/linux/fcntl.h
index 87e2dec79fea..56ff2100e021 100644
--- a/include/uapi/linux/fcntl.h
+++ b/include/uapi/linux/fcntl.h
@@ -153,6 +153,7 @@
object identity and may not be
usable with open_by_handle_at(2). */
#define AT_HANDLE_MNT_ID_UNIQUE 0x001 /* Return the u64 unique mount ID. */
+#define AT_HANDLE_CONNECTABLE 0x002 /* Request a connectable file handle */
#if defined(__KERNEL__)
#define AT_GETATTR_NOSEC 0x80000000
--
2.34.1
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH v3 3/3] fs: open_by_handle_at() support for decoding "explicit connectable" file handles
2024-10-08 15:21 [PATCH v3 0/3] API for exporting connectable file handles to userspace Amir Goldstein
2024-10-08 15:21 ` [PATCH v3 1/3] fs: prepare for "explicit connectable" file handles Amir Goldstein
2024-10-08 15:21 ` [PATCH v3 2/3] fs: name_to_handle_at() support " Amir Goldstein
@ 2024-10-08 15:21 ` Amir Goldstein
2024-10-08 18:37 ` Jeff Layton
2024-10-09 7:17 ` [PATCH v3 0/3] API for exporting connectable file handles to userspace Amir Goldstein
3 siblings, 1 reply; 12+ messages in thread
From: Amir Goldstein @ 2024-10-08 15:21 UTC (permalink / raw)
To: Jeff Layton
Cc: Christian Brauner, Jan Kara, Aleksa Sarai, Chuck Lever,
linux-fsdevel, linux-nfs
Teach open_by_handle_at(2) about the type format of "explicit connectable"
file handles that were created using the AT_HANDLE_CONNECTABLE flag to
name_to_handle_at(2).
When decoding an "explicit connectable" file handles, name_to_handle_at(2)
should fail if it cannot open a "connected" fd with known path, which is
accessible (to capable user) from mount fd path.
Note that this does not check if the path is accessible to the calling
user, just that it is accessible wrt the mount namesapce, so if there
is no "connected" alias, or if parts of the path are hidden in the
mount namespace, open_by_handle_at(2) will return -ESTALE.
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
---
fs/fhandle.c | 20 +++++++++++++++++++-
include/linux/exportfs.h | 2 +-
2 files changed, 20 insertions(+), 2 deletions(-)
diff --git a/fs/fhandle.c b/fs/fhandle.c
index 7b4c8945efcb..6a5458c3c6c9 100644
--- a/fs/fhandle.c
+++ b/fs/fhandle.c
@@ -246,7 +246,13 @@ static int vfs_dentry_acceptable(void *context, struct dentry *dentry)
if (!(ctx->flags & HANDLE_CHECK_SUBTREE) || d == root)
retval = 1;
- WARN_ON_ONCE(d != root && d != root->d_sb->s_root);
+ /*
+ * exportfs_decode_fh_raw() does not call acceptable() callback with
+ * a disconnected directory dentry, so we should have reached either
+ * mount fd directory or sb root.
+ */
+ if (ctx->fh_flags & EXPORT_FH_DIR_ONLY)
+ WARN_ON_ONCE(d != root && d != root->d_sb->s_root);
dput(d);
return retval;
}
@@ -349,6 +355,7 @@ static int handle_to_path(int mountdirfd, struct file_handle __user *ufh,
retval = -EINVAL;
goto out_path;
}
+
handle = kmalloc(struct_size(handle, f_handle, f_handle.handle_bytes),
GFP_KERNEL);
if (!handle) {
@@ -364,6 +371,17 @@ static int handle_to_path(int mountdirfd, struct file_handle __user *ufh,
goto out_handle;
}
+ /*
+ * If handle was encoded with AT_HANDLE_CONNECTABLE, verify that we
+ * are decoding an fd with connected path, which is accessible from
+ * the mount fd path.
+ */
+ if (f_handle.handle_type & FILEID_IS_CONNECTABLE) {
+ ctx.fh_flags |= EXPORT_FH_CONNECTABLE;
+ ctx.flags |= HANDLE_CHECK_SUBTREE;
+ }
+ if (f_handle.handle_type & FILEID_IS_DIR)
+ ctx.fh_flags |= EXPORT_FH_DIR_ONLY;
/* Filesystem code should not be exposed to user flags */
handle->handle_type &= ~FILEID_USER_FLAGS_MASK;
retval = do_handle_to_path(handle, path, &ctx);
diff --git a/include/linux/exportfs.h b/include/linux/exportfs.h
index 230b0e1d669d..a48d4c94ff74 100644
--- a/include/linux/exportfs.h
+++ b/include/linux/exportfs.h
@@ -171,7 +171,7 @@ struct fid {
/* Flags supported in encoded handle_type that is exported to user */
#define FILEID_IS_CONNECTABLE 0x10000
#define FILEID_IS_DIR 0x40000
-#define FILEID_VALID_USER_FLAGS (0)
+#define FILEID_VALID_USER_FLAGS (FILEID_IS_CONNECTABLE | FILEID_IS_DIR)
#define FILEID_USER_TYPE_IS_VALID(type) \
(!(FILEID_USER_FLAGS(type) & ~FILEID_VALID_USER_FLAGS))
--
2.34.1
^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [PATCH v3 1/3] fs: prepare for "explicit connectable" file handles
2024-10-08 15:21 ` [PATCH v3 1/3] fs: prepare for "explicit connectable" file handles Amir Goldstein
@ 2024-10-08 18:19 ` Jeff Layton
2024-10-08 20:31 ` Amir Goldstein
0 siblings, 1 reply; 12+ messages in thread
From: Jeff Layton @ 2024-10-08 18:19 UTC (permalink / raw)
To: Amir Goldstein
Cc: Christian Brauner, Jan Kara, Aleksa Sarai, Chuck Lever,
linux-fsdevel, linux-nfs
On Tue, 2024-10-08 at 17:21 +0200, Amir Goldstein wrote:
> We would like to use the high 16bit of the handle_type field to encode
> file handle traits, such as "connectable".
>
> In preparation for this change, make sure that filesystems do not return
> a handle_type value with upper bits set and that the open_by_handle_at(2)
> syscall rejects these handle types.
>
> Signed-off-by: Amir Goldstein <amir73il@gmail.com>
> ---
> fs/exportfs/expfs.c | 14 ++++++++++++--
> fs/fhandle.c | 6 ++++++
> include/linux/exportfs.h | 14 ++++++++++++++
> 3 files changed, 32 insertions(+), 2 deletions(-)
>
> diff --git a/fs/exportfs/expfs.c b/fs/exportfs/expfs.c
> index 4f2dd4ab4486..c8eb660fdde4 100644
> --- a/fs/exportfs/expfs.c
> +++ b/fs/exportfs/expfs.c
> @@ -382,14 +382,21 @@ int exportfs_encode_inode_fh(struct inode *inode, struct fid *fid,
> int *max_len, struct inode *parent, int flags)
> {
> const struct export_operations *nop = inode->i_sb->s_export_op;
> + enum fid_type type;
>
> if (!exportfs_can_encode_fh(nop, flags))
> return -EOPNOTSUPP;
>
> if (!nop && (flags & EXPORT_FH_FID))
> - return exportfs_encode_ino64_fid(inode, fid, max_len);
> + type = exportfs_encode_ino64_fid(inode, fid, max_len);
> + else
> + type = nop->encode_fh(inode, fid->raw, max_len, parent);
> +
> + if (WARN_ON_ONCE(FILEID_USER_FLAGS(type)))
> + return -EINVAL;
> +
The stack trace won't be very useful here. Rather than a WARN, it might
be better to dump out some info about the fstype (and maybe other
info?) that returned the bogus type value here. I'm pretty sure most
in-kernel fs's don't do this, but who knows what 3rd party fs's might
do.
> + return type;
>
> - return nop->encode_fh(inode, fid->raw, max_len, parent);
> }
> EXPORT_SYMBOL_GPL(exportfs_encode_inode_fh);
>
> @@ -436,6 +443,9 @@ exportfs_decode_fh_raw(struct vfsmount *mnt, struct fid *fid, int fh_len,
> char nbuf[NAME_MAX+1];
> int err;
>
> + if (WARN_ON_ONCE(FILEID_USER_FLAGS(fileid_type)))
> + return -EINVAL;
> +
This is called from do_handle_to_path() or nfsd_set_fh_dentry(), which
means that this fh comes from userland or from an NFS client. I don't
think we want to WARN because someone crafted a bogus fh and passed it
to us.
> /*
> * Try to get any dentry for the given file handle from the filesystem.
> */
> diff --git a/fs/fhandle.c b/fs/fhandle.c
> index 82df28d45cd7..c5792cf3c6e9 100644
> --- a/fs/fhandle.c
> +++ b/fs/fhandle.c
> @@ -307,6 +307,10 @@ static int handle_to_path(int mountdirfd, struct file_handle __user *ufh,
> retval = -EINVAL;
> goto out_path;
> }
> + if (!FILEID_USER_TYPE_IS_VALID(f_handle.handle_type)) {
> + retval = -EINVAL;
> + goto out_path;
> + }
> handle = kmalloc(struct_size(handle, f_handle, f_handle.handle_bytes),
> GFP_KERNEL);
> if (!handle) {
> @@ -322,6 +326,8 @@ static int handle_to_path(int mountdirfd, struct file_handle __user *ufh,
> goto out_handle;
> }
>
> + /* Filesystem code should not be exposed to user flags */
> + handle->handle_type &= ~FILEID_USER_FLAGS_MASK;
> retval = do_handle_to_path(handle, path, &ctx);
>
> out_handle:
> diff --git a/include/linux/exportfs.h b/include/linux/exportfs.h
> index 893a1d21dc1c..76a3050b3593 100644
> --- a/include/linux/exportfs.h
> +++ b/include/linux/exportfs.h
> @@ -160,6 +160,20 @@ struct fid {
> #define EXPORT_FH_FID 0x2 /* File handle may be non-decodeable */
> #define EXPORT_FH_DIR_ONLY 0x4 /* Only decode file handle for a directory */
>
> +/*
> + * Filesystems use only lower 8 bits of file_handle type for fid_type.
> + * name_to_handle_at() uses upper 16 bits of type as user flags to be
> + * interpreted by open_by_handle_at().
> + */
> +#define FILEID_USER_FLAGS_MASK 0xffff0000
> +#define FILEID_USER_FLAGS(type) ((type) & FILEID_USER_FLAGS_MASK)
> +
> +/* Flags supported in encoded handle_type that is exported to user */
> +#define FILEID_VALID_USER_FLAGS (0)
> +
> +#define FILEID_USER_TYPE_IS_VALID(type) \
> + (!(FILEID_USER_FLAGS(type) & ~FILEID_VALID_USER_FLAGS))
> +
> /**
> * struct export_operations - for nfsd to communicate with file systems
> * @encode_fh: encode a file handle fragment from a dentry
The rest looks reasonable.
--
Jeff Layton <jlayton@kernel.org>
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v3 2/3] fs: name_to_handle_at() support for "explicit connectable" file handles
2024-10-08 15:21 ` [PATCH v3 2/3] fs: name_to_handle_at() support " Amir Goldstein
@ 2024-10-08 18:31 ` Jeff Layton
2024-10-08 19:43 ` Amir Goldstein
0 siblings, 1 reply; 12+ messages in thread
From: Jeff Layton @ 2024-10-08 18:31 UTC (permalink / raw)
To: Amir Goldstein
Cc: Christian Brauner, Jan Kara, Aleksa Sarai, Chuck Lever,
linux-fsdevel, linux-nfs
On Tue, 2024-10-08 at 17:21 +0200, Amir Goldstein wrote:
> nfsd encodes "connectable" file handles for the subtree_check feature,
> which can be resolved to an open file with a connected path.
> So far, userspace nfs server could not make use of this functionality.
>
> Introduce a new flag AT_HANDLE_CONNECTABLE to name_to_handle_at(2).
> When used, the encoded file handle is "explicitly connectable".
>
> The "explicitly connectable" file handle sets bits in the high 16bit of
> the handle_type field, so open_by_handle_at(2) will know that it needs
> to open a file with a connected path.
>
> old kernels will now recognize the handle_type with high bits set,
> so "explicitly connectable" file handles cannot be decoded by
> open_by_handle_at(2) on old kernels.
>
> The flag AT_HANDLE_CONNECTABLE is not allowed together with either
> AT_HANDLE_FID or AT_EMPTY_PATH.
>
> Signed-off-by: Amir Goldstein <amir73il@gmail.com>
> ---
> fs/fhandle.c | 48 ++++++++++++++++++++++++++++++++++----
> include/linux/exportfs.h | 2 ++
> include/uapi/linux/fcntl.h | 1 +
> 3 files changed, 46 insertions(+), 5 deletions(-)
>
> diff --git a/fs/fhandle.c b/fs/fhandle.c
> index c5792cf3c6e9..7b4c8945efcb 100644
> --- a/fs/fhandle.c
> +++ b/fs/fhandle.c
> @@ -31,6 +31,14 @@ static long do_sys_name_to_handle(const struct path *path,
> if (!exportfs_can_encode_fh(path->dentry->d_sb->s_export_op, fh_flags))
> return -EOPNOTSUPP;
>
> + /*
> + * A request to encode a connectable handle for a disconnected dentry
> + * is unexpected since AT_EMPTY_PATH is not allowed.
> + */
> + if (fh_flags & EXPORT_FH_CONNECTABLE &&
> + WARN_ON(path->dentry->d_flags & DCACHE_DISCONNECTED))
> + return -EINVAL;
> +
Is it possible to get a DCACHE_DISCONNECTED dentry here? This thing
comes from a userland path walk (a'la name_to_handle_at()). That means
that it necessarily is connected.
I'd drop the fh_flags check, since it seems like having that set on any
dentry we get in this interface would be a bug.
> if (copy_from_user(&f_handle, ufh, sizeof(struct file_handle)))
> return -EFAULT;
>
> @@ -45,7 +53,7 @@ static long do_sys_name_to_handle(const struct path *path,
> /* convert handle size to multiple of sizeof(u32) */
> handle_dwords = f_handle.handle_bytes >> 2;
>
> - /* we ask for a non connectable maybe decodeable file handle */
> + /* Encode a possibly decodeable/connectable file handle */
> retval = exportfs_encode_fh(path->dentry,
> (struct fid *)handle->f_handle,
> &handle_dwords, fh_flags);
> @@ -67,8 +75,23 @@ static long do_sys_name_to_handle(const struct path *path,
> * non variable part of the file_handle
> */
> handle_bytes = 0;
> - } else
> + } else {
> + /*
> + * When asked to encode a connectable file handle, encode this
> + * property in the file handle itself, so that we later know
> + * how to decode it.
> + * For sanity, also encode in the file handle if the encoded
> + * object is a directory and verify this during decode, because
> + * decoding directory file handles is quite different than
> + * decoding connectable non-directory file handles.
> + */
> + if (fh_flags & EXPORT_FH_CONNECTABLE) {
> + handle->handle_type |= FILEID_IS_CONNECTABLE;
> + if (d_is_dir(path->dentry))
> + fh_flags |= FILEID_IS_DIR;
> + }
> retval = 0;
> + }
> /* copy the mount id */
> if (unique_mntid) {
> if (put_user(real_mount(path->mnt)->mnt_id_unique,
> @@ -109,15 +132,30 @@ SYSCALL_DEFINE5(name_to_handle_at, int, dfd, const char __user *, name,
> {
> struct path path;
> int lookup_flags;
> - int fh_flags;
> + int fh_flags = 0;
> int err;
>
> if (flag & ~(AT_SYMLINK_FOLLOW | AT_EMPTY_PATH | AT_HANDLE_FID |
> - AT_HANDLE_MNT_ID_UNIQUE))
> + AT_HANDLE_MNT_ID_UNIQUE | AT_HANDLE_CONNECTABLE))
> + return -EINVAL;
> +
> + /*
> + * AT_HANDLE_FID means there is no intention to decode file handle
> + * AT_HANDLE_CONNECTABLE means there is an intention to decode a
> + * connected fd (with known path), so these flags are conflicting.
> + * AT_EMPTY_PATH could be used along with a dfd that refers to a
> + * disconnected non-directory, which cannot be used to encode a
> + * connectable file handle, because its parent is unknown.
> + */
> + if (flag & AT_HANDLE_CONNECTABLE &&
> + flag & (AT_HANDLE_FID | AT_EMPTY_PATH))
> return -EINVAL;
> + else if (flag & AT_HANDLE_FID)
> + fh_flags |= EXPORT_FH_FID;
> + else if (flag & AT_HANDLE_CONNECTABLE)
> + fh_flags |= EXPORT_FH_CONNECTABLE;
>
> lookup_flags = (flag & AT_SYMLINK_FOLLOW) ? LOOKUP_FOLLOW : 0;
> - fh_flags = (flag & AT_HANDLE_FID) ? EXPORT_FH_FID : 0;
> if (flag & AT_EMPTY_PATH)
> lookup_flags |= LOOKUP_EMPTY;
> err = user_path_at(dfd, name, lookup_flags, &path);
> diff --git a/include/linux/exportfs.h b/include/linux/exportfs.h
> index 76a3050b3593..230b0e1d669d 100644
> --- a/include/linux/exportfs.h
> +++ b/include/linux/exportfs.h
> @@ -169,6 +169,8 @@ struct fid {
> #define FILEID_USER_FLAGS(type) ((type) & FILEID_USER_FLAGS_MASK)
>
> /* Flags supported in encoded handle_type that is exported to user */
> +#define FILEID_IS_CONNECTABLE 0x10000
> +#define FILEID_IS_DIR 0x40000
nit: why skip 0x20000 ?
> #define FILEID_VALID_USER_FLAGS (0)
>
> #define FILEID_USER_TYPE_IS_VALID(type) \
> diff --git a/include/uapi/linux/fcntl.h b/include/uapi/linux/fcntl.h
> index 87e2dec79fea..56ff2100e021 100644
> --- a/include/uapi/linux/fcntl.h
> +++ b/include/uapi/linux/fcntl.h
> @@ -153,6 +153,7 @@
> object identity and may not be
> usable with open_by_handle_at(2). */
> #define AT_HANDLE_MNT_ID_UNIQUE 0x001 /* Return the u64 unique mount ID. */
> +#define AT_HANDLE_CONNECTABLE 0x002 /* Request a connectable file handle */
>
> #if defined(__KERNEL__)
> #define AT_GETATTR_NOSEC 0x80000000
--
Jeff Layton <jlayton@kernel.org>
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v3 3/3] fs: open_by_handle_at() support for decoding "explicit connectable" file handles
2024-10-08 15:21 ` [PATCH v3 3/3] fs: open_by_handle_at() support for decoding " Amir Goldstein
@ 2024-10-08 18:37 ` Jeff Layton
2024-10-08 20:01 ` Amir Goldstein
0 siblings, 1 reply; 12+ messages in thread
From: Jeff Layton @ 2024-10-08 18:37 UTC (permalink / raw)
To: Amir Goldstein
Cc: Christian Brauner, Jan Kara, Aleksa Sarai, Chuck Lever,
linux-fsdevel, linux-nfs
On Tue, 2024-10-08 at 17:21 +0200, Amir Goldstein wrote:
> Teach open_by_handle_at(2) about the type format of "explicit connectable"
> file handles that were created using the AT_HANDLE_CONNECTABLE flag to
> name_to_handle_at(2).
>
> When decoding an "explicit connectable" file handles, name_to_handle_at(2)
> should fail if it cannot open a "connected" fd with known path, which is
> accessible (to capable user) from mount fd path.
>
> Note that this does not check if the path is accessible to the calling
> user, just that it is accessible wrt the mount namesapce, so if there
> is no "connected" alias, or if parts of the path are hidden in the
> mount namespace, open_by_handle_at(2) will return -ESTALE.
>
> Signed-off-by: Amir Goldstein <amir73il@gmail.com>
> ---
> fs/fhandle.c | 20 +++++++++++++++++++-
> include/linux/exportfs.h | 2 +-
> 2 files changed, 20 insertions(+), 2 deletions(-)
>
> diff --git a/fs/fhandle.c b/fs/fhandle.c
> index 7b4c8945efcb..6a5458c3c6c9 100644
> --- a/fs/fhandle.c
> +++ b/fs/fhandle.c
> @@ -246,7 +246,13 @@ static int vfs_dentry_acceptable(void *context, struct dentry *dentry)
>
> if (!(ctx->flags & HANDLE_CHECK_SUBTREE) || d == root)
> retval = 1;
> - WARN_ON_ONCE(d != root && d != root->d_sb->s_root);
> + /*
> + * exportfs_decode_fh_raw() does not call acceptable() callback with
> + * a disconnected directory dentry, so we should have reached either
> + * mount fd directory or sb root.
> + */
> + if (ctx->fh_flags & EXPORT_FH_DIR_ONLY)
> + WARN_ON_ONCE(d != root && d != root->d_sb->s_root);
I don't quite get the test for EXPORT_FH_DIR_ONLY here. Why does this
change require that instead of just continuing to WARN unconditionally?
> dput(d);
> return retval;
> }
> @@ -349,6 +355,7 @@ static int handle_to_path(int mountdirfd, struct file_handle __user *ufh,
> retval = -EINVAL;
> goto out_path;
> }
> +
> handle = kmalloc(struct_size(handle, f_handle, f_handle.handle_bytes),
> GFP_KERNEL);
> if (!handle) {
> @@ -364,6 +371,17 @@ static int handle_to_path(int mountdirfd, struct file_handle __user *ufh,
> goto out_handle;
> }
>
> + /*
> + * If handle was encoded with AT_HANDLE_CONNECTABLE, verify that we
> + * are decoding an fd with connected path, which is accessible from
> + * the mount fd path.
> + */
> + if (f_handle.handle_type & FILEID_IS_CONNECTABLE) {
> + ctx.fh_flags |= EXPORT_FH_CONNECTABLE;
> + ctx.flags |= HANDLE_CHECK_SUBTREE;
> + }
> + if (f_handle.handle_type & FILEID_IS_DIR)
> + ctx.fh_flags |= EXPORT_FH_DIR_ONLY;
> /* Filesystem code should not be exposed to user flags */
> handle->handle_type &= ~FILEID_USER_FLAGS_MASK;
> retval = do_handle_to_path(handle, path, &ctx);
> diff --git a/include/linux/exportfs.h b/include/linux/exportfs.h
> index 230b0e1d669d..a48d4c94ff74 100644
> --- a/include/linux/exportfs.h
> +++ b/include/linux/exportfs.h
> @@ -171,7 +171,7 @@ struct fid {
> /* Flags supported in encoded handle_type that is exported to user */
> #define FILEID_IS_CONNECTABLE 0x10000
> #define FILEID_IS_DIR 0x40000
> -#define FILEID_VALID_USER_FLAGS (0)
> +#define FILEID_VALID_USER_FLAGS (FILEID_IS_CONNECTABLE | FILEID_IS_DIR)
>
> #define FILEID_USER_TYPE_IS_VALID(type) \
> (!(FILEID_USER_FLAGS(type) & ~FILEID_VALID_USER_FLAGS))
--
Jeff Layton <jlayton@kernel.org>
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v3 2/3] fs: name_to_handle_at() support for "explicit connectable" file handles
2024-10-08 18:31 ` Jeff Layton
@ 2024-10-08 19:43 ` Amir Goldstein
0 siblings, 0 replies; 12+ messages in thread
From: Amir Goldstein @ 2024-10-08 19:43 UTC (permalink / raw)
To: Jeff Layton
Cc: Christian Brauner, Jan Kara, Aleksa Sarai, Chuck Lever,
linux-fsdevel, linux-nfs
On Tue, Oct 8, 2024 at 8:31 PM Jeff Layton <jlayton@kernel.org> wrote:
>
> On Tue, 2024-10-08 at 17:21 +0200, Amir Goldstein wrote:
> > nfsd encodes "connectable" file handles for the subtree_check feature,
> > which can be resolved to an open file with a connected path.
> > So far, userspace nfs server could not make use of this functionality.
> >
> > Introduce a new flag AT_HANDLE_CONNECTABLE to name_to_handle_at(2).
> > When used, the encoded file handle is "explicitly connectable".
> >
> > The "explicitly connectable" file handle sets bits in the high 16bit of
> > the handle_type field, so open_by_handle_at(2) will know that it needs
> > to open a file with a connected path.
> >
> > old kernels will now recognize the handle_type with high bits set,
> > so "explicitly connectable" file handles cannot be decoded by
> > open_by_handle_at(2) on old kernels.
> >
> > The flag AT_HANDLE_CONNECTABLE is not allowed together with either
> > AT_HANDLE_FID or AT_EMPTY_PATH.
> >
> > Signed-off-by: Amir Goldstein <amir73il@gmail.com>
> > ---
> > fs/fhandle.c | 48 ++++++++++++++++++++++++++++++++++----
> > include/linux/exportfs.h | 2 ++
> > include/uapi/linux/fcntl.h | 1 +
> > 3 files changed, 46 insertions(+), 5 deletions(-)
> >
> > diff --git a/fs/fhandle.c b/fs/fhandle.c
> > index c5792cf3c6e9..7b4c8945efcb 100644
> > --- a/fs/fhandle.c
> > +++ b/fs/fhandle.c
> > @@ -31,6 +31,14 @@ static long do_sys_name_to_handle(const struct path *path,
> > if (!exportfs_can_encode_fh(path->dentry->d_sb->s_export_op, fh_flags))
> > return -EOPNOTSUPP;
> >
> > + /*
> > + * A request to encode a connectable handle for a disconnected dentry
> > + * is unexpected since AT_EMPTY_PATH is not allowed.
> > + */
> > + if (fh_flags & EXPORT_FH_CONNECTABLE &&
> > + WARN_ON(path->dentry->d_flags & DCACHE_DISCONNECTED))
> > + return -EINVAL;
> > +
>
> Is it possible to get a DCACHE_DISCONNECTED dentry here? This thing
> comes from a userland path walk (a'la name_to_handle_at()). That means
> that it necessarily is connected.
Can't you get it with AT_EMPTY_PATH if dfd is obtained by open_by_handle()?
>
> I'd drop the fh_flags check, since it seems like having that set on any
> dentry we get in this interface would be a bug.
>
Well I don't know if giving a disconnected dentry to name_to_handle
is intentional, but it is not wrong, unless user actually requests a
connectable file handle. No?
> > if (copy_from_user(&f_handle, ufh, sizeof(struct file_handle)))
> > return -EFAULT;
> >
> > @@ -45,7 +53,7 @@ static long do_sys_name_to_handle(const struct path *path,
> > /* convert handle size to multiple of sizeof(u32) */
> > handle_dwords = f_handle.handle_bytes >> 2;
> >
> > - /* we ask for a non connectable maybe decodeable file handle */
> > + /* Encode a possibly decodeable/connectable file handle */
> > retval = exportfs_encode_fh(path->dentry,
> > (struct fid *)handle->f_handle,
> > &handle_dwords, fh_flags);
> > @@ -67,8 +75,23 @@ static long do_sys_name_to_handle(const struct path *path,
> > * non variable part of the file_handle
> > */
> > handle_bytes = 0;
> > - } else
> > + } else {
> > + /*
> > + * When asked to encode a connectable file handle, encode this
> > + * property in the file handle itself, so that we later know
> > + * how to decode it.
> > + * For sanity, also encode in the file handle if the encoded
> > + * object is a directory and verify this during decode, because
> > + * decoding directory file handles is quite different than
> > + * decoding connectable non-directory file handles.
> > + */
> > + if (fh_flags & EXPORT_FH_CONNECTABLE) {
> > + handle->handle_type |= FILEID_IS_CONNECTABLE;
> > + if (d_is_dir(path->dentry))
> > + fh_flags |= FILEID_IS_DIR;
> > + }
> > retval = 0;
> > + }
> > /* copy the mount id */
> > if (unique_mntid) {
> > if (put_user(real_mount(path->mnt)->mnt_id_unique,
> > @@ -109,15 +132,30 @@ SYSCALL_DEFINE5(name_to_handle_at, int, dfd, const char __user *, name,
> > {
> > struct path path;
> > int lookup_flags;
> > - int fh_flags;
> > + int fh_flags = 0;
> > int err;
> >
> > if (flag & ~(AT_SYMLINK_FOLLOW | AT_EMPTY_PATH | AT_HANDLE_FID |
> > - AT_HANDLE_MNT_ID_UNIQUE))
> > + AT_HANDLE_MNT_ID_UNIQUE | AT_HANDLE_CONNECTABLE))
> > + return -EINVAL;
> > +
> > + /*
> > + * AT_HANDLE_FID means there is no intention to decode file handle
> > + * AT_HANDLE_CONNECTABLE means there is an intention to decode a
> > + * connected fd (with known path), so these flags are conflicting.
> > + * AT_EMPTY_PATH could be used along with a dfd that refers to a
> > + * disconnected non-directory, which cannot be used to encode a
> > + * connectable file handle, because its parent is unknown.
> > + */
> > + if (flag & AT_HANDLE_CONNECTABLE &&
> > + flag & (AT_HANDLE_FID | AT_EMPTY_PATH))
> > return -EINVAL;
> > + else if (flag & AT_HANDLE_FID)
> > + fh_flags |= EXPORT_FH_FID;
> > + else if (flag & AT_HANDLE_CONNECTABLE)
> > + fh_flags |= EXPORT_FH_CONNECTABLE;
> >
> > lookup_flags = (flag & AT_SYMLINK_FOLLOW) ? LOOKUP_FOLLOW : 0;
> > - fh_flags = (flag & AT_HANDLE_FID) ? EXPORT_FH_FID : 0;
> > if (flag & AT_EMPTY_PATH)
> > lookup_flags |= LOOKUP_EMPTY;
> > err = user_path_at(dfd, name, lookup_flags, &path);
> > diff --git a/include/linux/exportfs.h b/include/linux/exportfs.h
> > index 76a3050b3593..230b0e1d669d 100644
> > --- a/include/linux/exportfs.h
> > +++ b/include/linux/exportfs.h
> > @@ -169,6 +169,8 @@ struct fid {
> > #define FILEID_USER_FLAGS(type) ((type) & FILEID_USER_FLAGS_MASK)
> >
> > /* Flags supported in encoded handle_type that is exported to user */
> > +#define FILEID_IS_CONNECTABLE 0x10000
> > +#define FILEID_IS_DIR 0x40000
>
> nit: why skip 0x20000 ?
Well in v2, the values were just shifting the EXPORT_FH_ flags left
so I kept it this way, although I am not sure if FILEID_ID_FID is ever
going to be useful, so I guess there is no good reason to skip 0x20000
Thanks,
Amir.
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v3 3/3] fs: open_by_handle_at() support for decoding "explicit connectable" file handles
2024-10-08 18:37 ` Jeff Layton
@ 2024-10-08 20:01 ` Amir Goldstein
0 siblings, 0 replies; 12+ messages in thread
From: Amir Goldstein @ 2024-10-08 20:01 UTC (permalink / raw)
To: Jeff Layton
Cc: Christian Brauner, Jan Kara, Aleksa Sarai, Chuck Lever,
linux-fsdevel, linux-nfs
On Tue, Oct 8, 2024 at 8:37 PM Jeff Layton <jlayton@kernel.org> wrote:
>
> On Tue, 2024-10-08 at 17:21 +0200, Amir Goldstein wrote:
> > Teach open_by_handle_at(2) about the type format of "explicit connectable"
> > file handles that were created using the AT_HANDLE_CONNECTABLE flag to
> > name_to_handle_at(2).
> >
> > When decoding an "explicit connectable" file handles, name_to_handle_at(2)
> > should fail if it cannot open a "connected" fd with known path, which is
> > accessible (to capable user) from mount fd path.
> >
> > Note that this does not check if the path is accessible to the calling
> > user, just that it is accessible wrt the mount namesapce, so if there
> > is no "connected" alias, or if parts of the path are hidden in the
> > mount namespace, open_by_handle_at(2) will return -ESTALE.
> >
> > Signed-off-by: Amir Goldstein <amir73il@gmail.com>
> > ---
> > fs/fhandle.c | 20 +++++++++++++++++++-
> > include/linux/exportfs.h | 2 +-
> > 2 files changed, 20 insertions(+), 2 deletions(-)
> >
> > diff --git a/fs/fhandle.c b/fs/fhandle.c
> > index 7b4c8945efcb..6a5458c3c6c9 100644
> > --- a/fs/fhandle.c
> > +++ b/fs/fhandle.c
> > @@ -246,7 +246,13 @@ static int vfs_dentry_acceptable(void *context, struct dentry *dentry)
> >
> > if (!(ctx->flags & HANDLE_CHECK_SUBTREE) || d == root)
> > retval = 1;
> > - WARN_ON_ONCE(d != root && d != root->d_sb->s_root);
> > + /*
> > + * exportfs_decode_fh_raw() does not call acceptable() callback with
> > + * a disconnected directory dentry, so we should have reached either
> > + * mount fd directory or sb root.
> > + */
> > + if (ctx->fh_flags & EXPORT_FH_DIR_ONLY)
> > + WARN_ON_ONCE(d != root && d != root->d_sb->s_root);
>
> I don't quite get the test for EXPORT_FH_DIR_ONLY here. Why does this
> change require that instead of just continuing to WARN unconditionally?
>
The reason is at the end of may_decode_fh(), you have:
ctx->fh_flags = EXPORT_FH_DIR_ONLY;
return true;
So until THIS patch, vfs_dentry_acceptable() was always called
with EXPORT_FH_DIR_ONLY.
THIS patch adds another use case where HANDLE_CHECK_SUBTREE
is being requested, but this time EXPORT_FH_DIR_ONLY is optional.
The comment above "exportfs_decode_fh_raw() does not call acceptable()..."
explains why the assertion is only true for directories.
Thanks,
Amir.
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v3 1/3] fs: prepare for "explicit connectable" file handles
2024-10-08 18:19 ` Jeff Layton
@ 2024-10-08 20:31 ` Amir Goldstein
2024-10-10 11:01 ` Amir Goldstein
0 siblings, 1 reply; 12+ messages in thread
From: Amir Goldstein @ 2024-10-08 20:31 UTC (permalink / raw)
To: Jeff Layton
Cc: Christian Brauner, Jan Kara, Aleksa Sarai, Chuck Lever,
linux-fsdevel, linux-nfs
On Tue, Oct 8, 2024 at 8:19 PM Jeff Layton <jlayton@kernel.org> wrote:
>
> On Tue, 2024-10-08 at 17:21 +0200, Amir Goldstein wrote:
> > We would like to use the high 16bit of the handle_type field to encode
> > file handle traits, such as "connectable".
> >
> > In preparation for this change, make sure that filesystems do not return
> > a handle_type value with upper bits set and that the open_by_handle_at(2)
> > syscall rejects these handle types.
> >
> > Signed-off-by: Amir Goldstein <amir73il@gmail.com>
> > ---
> > fs/exportfs/expfs.c | 14 ++++++++++++--
> > fs/fhandle.c | 6 ++++++
> > include/linux/exportfs.h | 14 ++++++++++++++
> > 3 files changed, 32 insertions(+), 2 deletions(-)
> >
> > diff --git a/fs/exportfs/expfs.c b/fs/exportfs/expfs.c
> > index 4f2dd4ab4486..c8eb660fdde4 100644
> > --- a/fs/exportfs/expfs.c
> > +++ b/fs/exportfs/expfs.c
> > @@ -382,14 +382,21 @@ int exportfs_encode_inode_fh(struct inode *inode, struct fid *fid,
> > int *max_len, struct inode *parent, int flags)
> > {
> > const struct export_operations *nop = inode->i_sb->s_export_op;
> > + enum fid_type type;
> >
> > if (!exportfs_can_encode_fh(nop, flags))
> > return -EOPNOTSUPP;
> >
> > if (!nop && (flags & EXPORT_FH_FID))
> > - return exportfs_encode_ino64_fid(inode, fid, max_len);
> > + type = exportfs_encode_ino64_fid(inode, fid, max_len);
> > + else
> > + type = nop->encode_fh(inode, fid->raw, max_len, parent);
> > +
> > + if (WARN_ON_ONCE(FILEID_USER_FLAGS(type)))
> > + return -EINVAL;
> > +
>
> The stack trace won't be very useful here. Rather than a WARN, it might
> be better to dump out some info about the fstype (and maybe other
> info?) that returned the bogus type value here. I'm pretty sure most
> in-kernel fs's don't do this, but who knows what 3rd party fs's might
> do.
>
Right. I changed to:
if (FILEID_USER_FLAGS(type)) {
pr_warn_once("%s: unexpected fh type value 0x%x from
fstype %s.\n",
__func__, type, inode->i_sb->s_type->name);
return -EINVAL;
}
> > + return type;
> >
> > - return nop->encode_fh(inode, fid->raw, max_len, parent);
> > }
> > EXPORT_SYMBOL_GPL(exportfs_encode_inode_fh);
> >
> > @@ -436,6 +443,9 @@ exportfs_decode_fh_raw(struct vfsmount *mnt, struct fid *fid, int fh_len,
> > char nbuf[NAME_MAX+1];
> > int err;
> >
> > + if (WARN_ON_ONCE(FILEID_USER_FLAGS(fileid_type)))
> > + return -EINVAL;
> > +
>
>
> This is called from do_handle_to_path() or nfsd_set_fh_dentry(), which
> means that this fh comes from userland or from an NFS client. I don't
> think we want to WARN because someone crafted a bogus fh and passed it
> to us.
>
Good point, I will remove the WARN and also fix the bug :-/
if (FILEID_USER_FLAGS(fileid_type))
return ERR_PTR(-EINVAL);
Pushed this and othe minor fixes to
https://github.com/amir73il/linux/commits/connectable-fh/
until we sort out the rest of your comments and maybe get more feedback.
Thanks for the review!
Amir.
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v3 0/3] API for exporting connectable file handles to userspace
2024-10-08 15:21 [PATCH v3 0/3] API for exporting connectable file handles to userspace Amir Goldstein
` (2 preceding siblings ...)
2024-10-08 15:21 ` [PATCH v3 3/3] fs: open_by_handle_at() support for decoding " Amir Goldstein
@ 2024-10-09 7:17 ` Amir Goldstein
3 siblings, 0 replies; 12+ messages in thread
From: Amir Goldstein @ 2024-10-09 7:17 UTC (permalink / raw)
To: Jeff Layton
Cc: Christian Brauner, Jan Kara, Aleksa Sarai, Chuck Lever,
linux-fsdevel, linux-nfs
On Tue, Oct 8, 2024 at 5:21 PM Amir Goldstein <amir73il@gmail.com> wrote:
>
> Jeff,
>
> These patches bring the NFS connectable file handles feature to
> userspace servers.
>
> They rely on Christian's and Aleksa's changes recently merged to v6.12.
>
> The API I chose for encoding conenctable file handles is pretty
> conventional (AT_HANDLE_CONNECTABLE).
>
> open_by_handle_at(2) does not have AT_ flags argument, but also, I find
> it more useful API that encoding a connectable file handle can mandate
> the resolving of a connected fd, without having to opt-in for a
> connected fd independently.
>
> I chose to implemnent this by using upper bits in the handle type field
> It may be valid (?) for filesystems to return a handle type with upper
> bits set, but AFAIK, no in-tree filesystem does that.
> I added some assertions just in case.
FYI, version with softened assertions at:
https://github.com/amir73il/linux/commits/connectable-fh/
fstest at:
https://github.com/amir73il/xfstests/commits/connectable-fh/
man-page at:
https://github.com/amir73il/man-pages/commits/connectable-fh/
>
> Thanks,
> Amir.
>
> Changes since v2 [2]:
> - Use bit arithmetics instead of bitfileds (Jeff)
> - Add assertions about use of high type bits
>
> Changes since v1 [1]:
> - Assert on encode for disconnected path (Jeff)
> - Don't allow AT_HANDLE_CONNECTABLE with AT_EMPTY_PATH
> - Drop the O_PATH mount_fd API hack (Jeff)
> - Encode an explicit "connectable" flag in handle type
>
> [1] https://lore.kernel.org/linux-fsdevel/20240919140611.1771651-1-amir73il@gmail.com/
> [2] https://lore.kernel.org/linux-fsdevel/20240923082829.1910210-1-amir73il@gmail.com/
>
> Amir Goldstein (3):
> fs: prepare for "explicit connectable" file handles
> fs: name_to_handle_at() support for "explicit connectable" file
> handles
> fs: open_by_handle_at() support for decoding "explicit connectable"
> file handles
>
> fs/exportfs/expfs.c | 14 ++++++--
> fs/fhandle.c | 74 ++++++++++++++++++++++++++++++++++----
> include/linux/exportfs.h | 16 +++++++++
> include/uapi/linux/fcntl.h | 1 +
> 4 files changed, 97 insertions(+), 8 deletions(-)
>
> --
> 2.34.1
>
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v3 1/3] fs: prepare for "explicit connectable" file handles
2024-10-08 20:31 ` Amir Goldstein
@ 2024-10-10 11:01 ` Amir Goldstein
0 siblings, 0 replies; 12+ messages in thread
From: Amir Goldstein @ 2024-10-10 11:01 UTC (permalink / raw)
To: Jeff Layton
Cc: Christian Brauner, Jan Kara, Aleksa Sarai, Chuck Lever,
linux-fsdevel, linux-nfs
On Tue, Oct 8, 2024 at 10:31 PM Amir Goldstein <amir73il@gmail.com> wrote:
>
> On Tue, Oct 8, 2024 at 8:19 PM Jeff Layton <jlayton@kernel.org> wrote:
> >
> > On Tue, 2024-10-08 at 17:21 +0200, Amir Goldstein wrote:
> > > We would like to use the high 16bit of the handle_type field to encode
> > > file handle traits, such as "connectable".
> > >
> > > In preparation for this change, make sure that filesystems do not return
> > > a handle_type value with upper bits set and that the open_by_handle_at(2)
> > > syscall rejects these handle types.
> > >
> > > Signed-off-by: Amir Goldstein <amir73il@gmail.com>
> > > ---
> > > fs/exportfs/expfs.c | 14 ++++++++++++--
> > > fs/fhandle.c | 6 ++++++
> > > include/linux/exportfs.h | 14 ++++++++++++++
> > > 3 files changed, 32 insertions(+), 2 deletions(-)
> > >
> > > diff --git a/fs/exportfs/expfs.c b/fs/exportfs/expfs.c
> > > index 4f2dd4ab4486..c8eb660fdde4 100644
> > > --- a/fs/exportfs/expfs.c
> > > +++ b/fs/exportfs/expfs.c
> > > @@ -382,14 +382,21 @@ int exportfs_encode_inode_fh(struct inode *inode, struct fid *fid,
> > > int *max_len, struct inode *parent, int flags)
> > > {
> > > const struct export_operations *nop = inode->i_sb->s_export_op;
> > > + enum fid_type type;
> > >
> > > if (!exportfs_can_encode_fh(nop, flags))
> > > return -EOPNOTSUPP;
> > >
> > > if (!nop && (flags & EXPORT_FH_FID))
> > > - return exportfs_encode_ino64_fid(inode, fid, max_len);
> > > + type = exportfs_encode_ino64_fid(inode, fid, max_len);
> > > + else
> > > + type = nop->encode_fh(inode, fid->raw, max_len, parent);
> > > +
> > > + if (WARN_ON_ONCE(FILEID_USER_FLAGS(type)))
> > > + return -EINVAL;
> > > +
> >
> > The stack trace won't be very useful here. Rather than a WARN, it might
> > be better to dump out some info about the fstype (and maybe other
> > info?) that returned the bogus type value here. I'm pretty sure most
> > in-kernel fs's don't do this, but who knows what 3rd party fs's might
> > do.
> >
>
> Right. I changed to:
>
> if (FILEID_USER_FLAGS(type)) {
> pr_warn_once("%s: unexpected fh type value 0x%x from
> fstype %s.\n",
> __func__, type, inode->i_sb->s_type->name);
> return -EINVAL;
> }
>
>
FYI, following Jan's comment about mixing bitwise with negative values,
I changes this to:
if (type > 0 && FILEID_USER_FLAGS(type)) {
pr_warn_once("%s: unexpected fh type value 0x%x from
fstype %s.\n",
__func__, type, inode->i_sb->s_type->name);
return -EINVAL;
}
return type;
because ->encode_fh() method are allowed to return a negative error
(e.g. -EOVERFLOW)
> > > + return type;
> > >
> > > - return nop->encode_fh(inode, fid->raw, max_len, parent);
> > > }
> > > EXPORT_SYMBOL_GPL(exportfs_encode_inode_fh);
> > >
> > > @@ -436,6 +443,9 @@ exportfs_decode_fh_raw(struct vfsmount *mnt, struct fid *fid, int fh_len,
> > > char nbuf[NAME_MAX+1];
> > > int err;
> > >
> > > + if (WARN_ON_ONCE(FILEID_USER_FLAGS(fileid_type)))
> > > + return -EINVAL;
> > > +
> >
> >
> > This is called from do_handle_to_path() or nfsd_set_fh_dentry(), which
> > means that this fh comes from userland or from an NFS client. I don't
> > think we want to WARN because someone crafted a bogus fh and passed it
> > to us.
> >
>
> Good point, I will remove the WARN and also fix the bug :-/
>
> if (FILEID_USER_FLAGS(fileid_type))
> return ERR_PTR(-EINVAL);
>
And changed this to:
@@ -436,6 +446,9 @@ exportfs_decode_fh_raw(struct vfsmount *mnt,
struct fid *fid, int fh_len,
char nbuf[NAME_MAX+1];
int err;
+ if (fileid_type < 0 || FILEID_USER_FLAGS(fileid_type))
+ return ERR_PTR(-EINVAL);
+
> Pushed this and othe minor fixes to
> https://github.com/amir73il/linux/commits/connectable-fh/
> until we sort out the rest of your comments and maybe get more feedback.
>
If no further comments I will post v4.
Thanks,
Amir.
^ permalink raw reply [flat|nested] 12+ messages in thread
end of thread, other threads:[~2024-10-10 11:01 UTC | newest]
Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-10-08 15:21 [PATCH v3 0/3] API for exporting connectable file handles to userspace Amir Goldstein
2024-10-08 15:21 ` [PATCH v3 1/3] fs: prepare for "explicit connectable" file handles Amir Goldstein
2024-10-08 18:19 ` Jeff Layton
2024-10-08 20:31 ` Amir Goldstein
2024-10-10 11:01 ` Amir Goldstein
2024-10-08 15:21 ` [PATCH v3 2/3] fs: name_to_handle_at() support " Amir Goldstein
2024-10-08 18:31 ` Jeff Layton
2024-10-08 19:43 ` Amir Goldstein
2024-10-08 15:21 ` [PATCH v3 3/3] fs: open_by_handle_at() support for decoding " Amir Goldstein
2024-10-08 18:37 ` Jeff Layton
2024-10-08 20:01 ` Amir Goldstein
2024-10-09 7:17 ` [PATCH v3 0/3] API for exporting connectable file handles to userspace Amir Goldstein
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).