[PATCH] nfsd: do not allow exporting of special kernel filesystems

Amir Goldstein
2026-01-21T08:50:31Z

pidfs and nsfs recently gained support for encode/decode of file handles
via name_to_handle_at(2)/opan_by_handle_at(2).

These special kernel filesystems have custom ->open() and ->permission()
export methods, which nfsd does not respect and it was never meant to be
used for exporting those filesystems by nfsd.

Therefore, do not allow nfsd to export filesystems with custom ->open()
or ->permission() methods.

Fixes: b3caba8f7a34a ("pidfs: implement file handle support")
Fixes: 5222470b2fbb3 ("nsfs: support file handles")
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
---
fs/nfsd/export.c | 21 +++++++++++++--------
1 file changed, 13 insertions(+), 8 deletions(-)

Christian,

I had enough of the stable file handles discussion [1].

This patch which I already suggested [2] on week ago, states a justified
technical reason why pidfs and nsfs should not be exported by nfsd,
so let's use this technical reasoning and stop the philosophic discussions
about what is a stable file handle is please.

Regarding cgroupfs, we can either deal with it later or not - it is not
a clear but as pidfs and nsfs which absolutely should be fixed
retroactively in stable kernels.

If you think that cgroupfs could benefit from "exhaustive" file handles [3]
then we can implement open_by_handle_at(FD_CGROUPFS_ROOT, ... and that
would classify cgroupfs the same as pidfs and nsfs.

Thanks,
Amir.

[1] https://lore.kernel.org/linux-fsdevel/20250912-work-namespace-v2-0-1a247645cef5@kernel.org/
[2] https://lore.kernel.org/linux-fsdevel/CAOQ4uxhkaGFtQRzTj2xaf2GJucoAY5CGiyUjB=8YA2zTbOtFvw@mail.gmail.com/
[3] https://lore.kernel.org/linux-fsdevel/20250912-work-namespace-v2-29-1a247645cef5@kernel.org/

diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c
index 2a1499f2ad196..232dacac611e9 100644
--- a/fs/nfsd/export.c
+++ b/fs/nfsd/export.c
@@ -405,6 +405,7 @@ static struct svc_export *svc_export_lookup(struct svc_export *);
static int check_export(const struct path *path, int *flags, unsigned char *uuid)
{
struct inode *inode = d_inode(path->dentry);
+ const struct export_operations *nop = inode->i_sb->s_export_op;

/*
* We currently export only dirs, regular files, and (for v4
@@ -422,13 +423,12 @@ static int check_export(const struct path *path, int *flags, unsigned char *uuid
if (*flags & NFSEXP_V4ROOT)
*flags |= NFSEXP_READONLY;

- /* There are two requirements on a filesystem to be exportable.
- * 1: We must be able to identify the filesystem from a number.
- * either a device number (so FS_REQUIRES_DEV needed)
- * or an FSID number (so NFSEXP_FSID or ->uuid is needed).
- * 2: We must be able to find an inode from a filehandle.
- * This means that s_export_op must be set.
- * 3: We must not currently be on an idmapped mount.
+ /*
+ * The requirements for a filesystem to be exportable:
+ * 1. The filehandle must identify a filesystem by number
+ * 2. The filehandle must uniquely identify an inode
+ * 3. The filesystem must not have custom filehandle open/perm methods
+ * 4. The requested file must not reside on an idmapped mount
*/
if (!(inode->i_sb->s_type->fs_flags & FS_REQUIRES_DEV) &&
!(*flags & NFSEXP_FSID) &&
@@ -437,11 +437,16 @@ static int check_export(const struct path *path, int *flags, unsigned char *uuid
return -EINVAL;
}

- if (!exportfs_can_decode_fh(inode->i_sb->s_export_op)) {
+ if (!exportfs_can_decode_fh(nop)) {
dprintk("exp_export: export of invalid fs type.\n");
return -EINVAL;
}

+ if (nop->open || nop->permission) {
+ dprintk("exp_export: export of non-standard fs type.\n");
+ return -EINVAL;
+ }
+
if (is_idmapped_mnt(path->mnt)) {
dprintk("exp_export: export of idmapped mounts not yet supported.\n");
return -EINVAL;
--
2.52.0