summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeff Layton <jlayton@kernel.org>2026-05-21 13:51:43 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2026-07-04 13:42:27 +0200
commit1e96239fddcefacf6afe6c498357be68eacbcabc (patch)
tree825fc460edfbacfef926156638c432c6689ce3fc
parent1e04be34cafae119e82bcaccd6d28a20f72a3647 (diff)
downloadlinux-stable-1e96239fddcefacf6afe6c498357be68eacbcabc.tar.gz
linux-stable-1e96239fddcefacf6afe6c498357be68eacbcabc.zip
nfsd: fix posix_acl leak on SETACL decode failure
commit 0853ac544c590880d797b04daa33fcb72b6be0e1 upstream. nfsaclsvc_decode_setaclargs() and nfs3svc_decode_setaclargs() each call nfs_stream_decode_acl() twice, first for NFS_ACL and then for NFS_DFACL. Each successful call transfers ownership of a freshly allocated posix_acl into argp->acl_access or argp->acl_default. If the first call succeeds but the second fails, the decoder returns false and argp->acl_access is left dangling. ACLPROC2_SETACL.pc_release was wired to nfssvc_release_attrstat and ACLPROC3_SETACL.pc_release was wired to nfs3svc_release_fhandle. Both only call fh_put() and have no knowledge of the ACL fields on argp. The posix_acl_release() pairs sat at the out: labels inside nfsacld_proc_setacl() and nfsd3_proc_setacl(), but svc_process() skips pc_func when pc_decode returns false, so that cleanup is unreachable on decode failure: svc_process_common() pc_decode() /* decode_setaclargs: false */ /* pc_func skipped */ pc_release() /* fh_put only -- ACLs leaked */ The orphaned posix_acl is leaked for the lifetime of the server. Fix by adding nfsaclsvc_release_setacl() and nfs3svc_release_setacl(), which release both argp->acl_access and argp->acl_default in addition to fh_put(), and wiring them as pc_release for their respective SETACL procedures. pc_release runs on every path svc_process() takes after decode, including decode failure, so the posix_acl_release() pairs are removed from the proc functions' out: labels to keep ownership in one place. This matches the existing release_getacl() pattern used by the sibling GETACL procedures. Fixes: a257cdd0e217 ("[PATCH] NFSD: Add server support for NFSv3 ACLs.") Cc: stable@vger.kernel.org Assisted-by: kres:claude-opus-4-7 Signed-off-by: Jeff Layton <jlayton@kernel.org> Signed-off-by: Chuck Lever <chuck.lever@oracle.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--fs/nfsd/nfs2acl.c17
-rw-r--r--fs/nfsd/nfs3acl.c17
2 files changed, 24 insertions, 10 deletions
diff --git a/fs/nfsd/nfs2acl.c b/fs/nfsd/nfs2acl.c
index f1f32ad4f42c..bdcfab9e3a32 100644
--- a/fs/nfsd/nfs2acl.c
+++ b/fs/nfsd/nfs2acl.c
@@ -131,10 +131,7 @@ static __be32 nfsacld_proc_setacl(struct svc_rqst *rqstp)
resp->status = fh_getattr(fh, &resp->stat);
out:
- /* argp->acl_{access,default} may have been allocated in
- nfssvc_decode_setaclargs. */
- posix_acl_release(argp->acl_access);
- posix_acl_release(argp->acl_default);
+ /* argp->acl_{access,default} are released in nfsaclsvc_release_setacl. */
return rpc_success;
out_drop_lock:
@@ -312,6 +309,16 @@ static void nfsaclsvc_release_access(struct svc_rqst *rqstp)
struct nfsd3_voidargs { int dummy; };
+static void nfsaclsvc_release_setacl(struct svc_rqst *rqstp)
+{
+ struct nfsd3_setaclargs *argp = rqstp->rq_argp;
+ struct nfsd_attrstat *resp = rqstp->rq_resp;
+
+ fh_put(&resp->fh);
+ posix_acl_release(argp->acl_access);
+ posix_acl_release(argp->acl_default);
+}
+
#define ST 1 /* status*/
#define AT 21 /* attributes */
#define pAT (1+AT) /* post attributes - conditional */
@@ -345,7 +352,7 @@ static const struct svc_procedure nfsd_acl_procedures2[5] = {
.pc_func = nfsacld_proc_setacl,
.pc_decode = nfsaclsvc_decode_setaclargs,
.pc_encode = nfssvc_encode_attrstatres,
- .pc_release = nfssvc_release_attrstat,
+ .pc_release = nfsaclsvc_release_setacl,
.pc_argsize = sizeof(struct nfsd3_setaclargs),
.pc_argzero = sizeof(struct nfsd3_setaclargs),
.pc_ressize = sizeof(struct nfsd_attrstat),
diff --git a/fs/nfsd/nfs3acl.c b/fs/nfsd/nfs3acl.c
index d7af28f44504..4e9c0f2ef796 100644
--- a/fs/nfsd/nfs3acl.c
+++ b/fs/nfsd/nfs3acl.c
@@ -118,10 +118,7 @@ out_drop_lock:
out_errno:
resp->status = nfserrno(error);
out:
- /* argp->acl_{access,default} may have been allocated in
- nfs3svc_decode_setaclargs. */
- posix_acl_release(argp->acl_access);
- posix_acl_release(argp->acl_default);
+ /* argp->acl_{access,default} are released in nfs3svc_release_setacl. */
return rpc_success;
}
@@ -225,6 +222,16 @@ static void nfs3svc_release_getacl(struct svc_rqst *rqstp)
struct nfsd3_voidargs { int dummy; };
+static void nfs3svc_release_setacl(struct svc_rqst *rqstp)
+{
+ struct nfsd3_setaclargs *argp = rqstp->rq_argp;
+ struct nfsd3_attrstat *resp = rqstp->rq_resp;
+
+ fh_put(&resp->fh);
+ posix_acl_release(argp->acl_access);
+ posix_acl_release(argp->acl_default);
+}
+
#define ST 1 /* status*/
#define AT 21 /* attributes */
#define pAT (1+AT) /* post attributes - conditional */
@@ -258,7 +265,7 @@ static const struct svc_procedure nfsd_acl_procedures3[3] = {
.pc_func = nfsd3_proc_setacl,
.pc_decode = nfs3svc_decode_setaclargs,
.pc_encode = nfs3svc_encode_setaclres,
- .pc_release = nfs3svc_release_fhandle,
+ .pc_release = nfs3svc_release_setacl,
.pc_argsize = sizeof(struct nfsd3_setaclargs),
.pc_argzero = sizeof(struct nfsd3_setaclargs),
.pc_ressize = sizeof(struct nfsd3_attrstat),