From 3e2c79360c6a89975ec5b5a7d4ef937e4db91a27 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Tue, 26 May 2026 15:27:58 +1000 Subject: [PATCH] nfsd: fix possible fh_compose of wrong dentry in nfsd4_create_file() dentry_create() can hypothetically provide a different dentry than the one passed in. This could happen, for example, if the exported filesystem is NFS, and the server returned to OPEN a filehandle which matched a directory that was already in the dcache. Clearly this would not be expected! If this were to happen the dentry (child) that was already stored in resfhp could be freed and later dereferenced. We shouldn't call fh_compose() until we are certain that we have the final dentry, so this patch moved the fh_compose() call to two places: one for the case where the target already exists, and one after dentry_create() where it was created. Fixes: 64a989dbd144 ("VFS/knfsd: Teach dentry_create() to use atomic_open()") Cc: stable@vger.kernel.org Signed-off-by: NeilBrown Link: https://patch.msgid.link/20260526053004.4014491-2-neilb@ownmail.net Signed-off-by: Chuck Lever Reviewed-by: Jeff Layton Reviewed-by: Benjamin Coddington --- fs/nfsd/nfs4proc.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 3024d51d6fb7..c16ccb403a8d 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -306,10 +306,6 @@ nfsd4_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp, goto out; } - status = fh_compose(resfhp, fhp->fh_export, child, fhp); - if (status != nfs_ok) - goto out; - v_mtime = 0; v_atime = 0; if (nfsd4_create_is_exclusive(open->op_createmode)) { @@ -335,6 +331,10 @@ nfsd4_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp, if (status != nfs_ok) goto out; + status = fh_compose(resfhp, fhp->fh_export, child, fhp); + if (status != nfs_ok) + goto out; + switch (open->op_createmode) { case NFS4_CREATE_UNCHECKED: if (!d_is_reg(child)) @@ -385,6 +385,10 @@ nfsd4_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp, open->op_created = true; fh_fill_post_attrs(fhp); + status = fh_compose(resfhp, fhp->fh_export, child, fhp); + if (status != nfs_ok) + goto out; + /* A newly created file already has a file size of zero. */ if ((iap->ia_valid & ATTR_SIZE) && (iap->ia_size == 0)) iap->ia_valid &= ~ATTR_SIZE;