summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNeilBrown <neil@brown.name>2026-05-26 15:27:58 +1000
committerChuck Lever <cel@kernel.org>2026-08-03 09:14:35 -0400
commit3e2c79360c6a89975ec5b5a7d4ef937e4db91a27 (patch)
tree04be693fab689e7bdfe5d159fc84d3b59608cc02
parent036c1b182f4da65363e79ec0ac276edc6b7296e5 (diff)
downloadlinux-stable-3e2c79360c6a89975ec5b5a7d4ef937e4db91a27.tar.gz
linux-stable-3e2c79360c6a89975ec5b5a7d4ef937e4db91a27.zip
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 <neil@brown.name> Link: https://patch.msgid.link/20260526053004.4014491-2-neilb@ownmail.net Signed-off-by: Chuck Lever <chuck.lever@oracle.com> Reviewed-by: Jeff Layton <jlayton@kernel.org> Reviewed-by: Benjamin Coddington <bcodding@hammerspace.com>
-rw-r--r--fs/nfsd/nfs4proc.c12
1 files 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;