nfsd: release OPEN-decoded posix ACLs via op_release
Subsystems (2)
Jeff Layton
maintainerPATCH v2 1/1 nfsd: release OPEN-decoded posix ACLs via op_release
nfsd4_decode_createhow4() calls nfsd4_decode_fattr4(), which allocates refcounted struct posix_acl objects via posix_acl_alloc() and stores them in open->op_pacl and open->op_dpacl. These pointers must be released once the OPEN compound finishes.
When nfsd4_decode_open_claim4() returns a non-seqid-mutating error, the dispatcher short-circuits before op_func runs:
nfsd4_proc_compound()
opdesc->op_func == nfsd4_open_omfg
if (!seqid_mutating_err(ntohl(op->status)))
return op->status; /* nfsd4_open() never runs */
opdesc->op_release(&op->u) /* must still release op_pacl/op_dpacl */Before this change OP_OPEN had no .op_release in nfsd4_ops[], and the release pair lived inside nfsd4_open() at its out_err: label. On the short-circuit path nfsd4_open() is never invoked, so both posix_acl refs leak on every malformed OPEN compound that carries valid POSIX ACL createhow4 attributes.
Add nfsd4_open_release() and wire it as .op_release for OP_OPEN. posix_acl_release() is NULL-safe, so the single release site covers both the normal path and the nfsd4_open_omfg short-circuit. Remove the matching posix_acl_release() pair from nfsd4_open()'s out_err:
label to avoid double-releasing.
The compound loop has two encoding branches: nfsd4_encode_operation() for normal ops, and nfsd4_encode_replay() for v4.0 replayed ops. op_release was only called from nfsd4_encode_operation(), so resources attached to op->u leak on the replay path. Add an op_release call to the replay branch as well to ensure cleanup on every path.
---
Changes in v2:
- Ensure that op_release is called in the v4.0 replay case as well
- Link to v1: https://lore.kernel.org/r/[email protected]
--- fs/nfsd/nfs4proc.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-)
fs/nfsd/nfs4proc.c +10 -2
@@ -681,8 +681,6 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,nfsd4_cleanup_open_state (cstate, open);nfsd4_bump_seqid (cstate, status); out_err: -posix_acl_release (open->op_dpacl); -posix_acl_release (open->op_pacl);return status; }
@@ -704,6 +702,13 @@ static __be32 nfsd4_open_omfg(struct svc_rqst *rqstp, struct nfsd4_compound_statreturn nfsd4_open (rqstp, cstate, &op->u); } +static void +nfsd4_open_release (union nfsd4_op_u *u) +{ +posix_acl_release (u->open.op_dpacl); +posix_acl_release (u->open.op_pacl); +} +/* * filehandle-manipulating ops. */
@@ -3214,6 +3219,8 @@ nfsd4_proc_compound(struct svc_rqst *rqstp) op->replay = &cstate->replay_owner->so_replay;nfsd4_encode_replay (resp->xdr, op); status = op->status = op->replay->rp_status; +if (op->opdesc->op_release) + op->opdesc->op_release (&op->u); }else {nfsd4_encode_operation (resp, op); status = op->status;
@@ -3718,6 +3725,7 @@ static const struct nfsd4_operation nfsd4_ops[] = { }, [OP_OPEN] = { .op_func = nfsd4_open, + .op_release = nfsd4_open_release, .op_flags = OP_HANDLES_WRONGSEC | OP_MODIFIES_SOMETHING, .op_name = "OP_OPEN", .op_rsize_bop = nfsd4_open_rsize,
---
base-commit: 6c0004650ba248a12937ada16f9ba961b35ce2b5
change-id: 20260531-nfsd-testing-9122bf51ce95
Best regards,
Signature · 1 line
Jeff Layton <[email protected]>
Quoted 72 lines · Jeff Layton
nfsd4_decode_createhow4()callsnfsd4_decode_fattr4(), which allocates refcounted structposix_aclobjects viaposix_acl_alloc()and stores them inopen->op_paclandopen->op_dpacl. These pointers must be released once the OPEN compound finishes.When
nfsd4_decode_open_claim4()returns a non-seqid-mutating error, the dispatcher short-circuits beforeop_funcruns:nfsd4_proc_compound() opdesc->op_func == nfsd4_open_omfg if (!seqid_mutating_err(ntohl(op->status))) return op->status; /* nfsd4_open() never runs */ opdesc->op_release(&op->u) /* must still release op_pacl/op_dpacl */Before this change
OP_OPENhad no .op_release in nfsd4_ops[], and the release pair lived insidenfsd4_open()at itsout_err: label. On the short-circuit pathnfsd4_open()is never invoked, so bothposix_aclrefs leak on every malformed OPEN compound that carries valid POSIX ACL createhow4 attributes.Add
nfsd4_open_release()and wire it as .op_release forOP_OPEN.posix_acl_release()is NULL-safe, so the single release site covers both the normal path and thenfsd4_open_omfgshort-circuit. Remove the matchingposix_acl_release()pair from nfsd4_open()'sout_err:
label to avoid double-releasing.The compound loop has two encoding branches:
nfsd4_encode_operation()for normal ops, andnfsd4_encode_replay()for v4.0 replayed ops.op_releasewas only called fromnfsd4_encode_operation(), so resources attached toop->uleak on the replay path. Add anop_releasecall to the replay branch as well to ensure cleanup on every path.Fixes 5fc51dfc2eb1 ("NFSD: Add support for XDR decoding POSIX draft ACLs")Signed-off-by Chris Mason <[email protected]>Reviewed-by Chuck Lever <[email protected]>Signed-off-by Jeff Layton <[email protected]>---
Changes in v2:
- Ensure thatop_releaseis called in the v4.0 replay case as well
- Link to v1: https://lore.kernel.org/r/[email protected]--- fs/nfsd/nfs4proc.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-)fs/nfsd/nfs4proc.c +7
-2@@ -681,8 +681,6 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,nfsd4_cleanup_open_state (cstate, open);nfsd4_bump_seqid (cstate, status); out_err: -posix_acl_release (open->op_dpacl); -posix_acl_release (open->op_pacl);return status; }@@ -704,6 +702,13 @@ static __be32 nfsd4_open_omfg(struct svc_rqst *rqstp, struct nfsd4_compound_statreturn nfsd4_open (rqstp, cstate, &op->u); } +static void +nfsd4_open_release (union nfsd4_op_u *u) +{ +posix_acl_release (u->open.op_dpacl); +posix_acl_release (u->open.op_pacl); +} +/* * filehandle-manipulating ops. */
fs/nfsd/nfs4proc.c nfsd4_proc_compound(struct svc_rqst *rqstp) · line 3226
Quoted 8 lines
fs/nfsd/nfs4proc.c +2
-0@@ -3214,6 +3219,8 @@ nfsd4_proc_compound(struct svc_rqst *rqstp) op->replay = &cstate->replay_owner->so_replay;nfsd4_encode_replay (resp->xdr, op); status = op->status = op->replay->rp_status; +if (op->opdesc->op_release) + op->opdesc->op_release (&op->u); }else {nfsd4_encode_operation (resp, op); status = op->status;
I think this patch is good, but I think it would be even better if the ->op_release() call were moved out of nfsd4_encode_operation() and places after this if-else. Then there would be only one call-site in a fairly obviously-correct place.
But:
for if you just want to stick with this version.
Thanks,
NeilBrown
Quoted 18 lines
fs/nfsd/nfs4proc.c +1
-1@@ -3718,6 +3725,7 @@ static const struct nfsd4_operation nfsd4_ops[] = { }, [OP_OPEN] = { .op_func = nfsd4_open, + .op_release = nfsd4_open_release, .op_flags = OP_HANDLES_WRONGSEC | OP_MODIFIES_SOMETHING, .op_name = "OP_OPEN", .op_rsize_bop = nfsd4_open_rsize, ---base-commit:
6c0004650ba248a12937ada16f9ba961b35ce2b5
change-id: 20260531-nfsd-testing-9122bf51ce95Best regards,
Signature · 1 line
Jeff Layton <[email protected]>
Jeff Layton
maintainerQuoted 87 lines · NeilBrown
Quoted 72 lines · Jeff Layton
nfsd4_decode_createhow4()callsnfsd4_decode_fattr4(), which allocates refcounted structposix_aclobjects viaposix_acl_alloc()and stores them inopen->op_paclandopen->op_dpacl. These pointers must be released once the OPEN compound finishes.When
nfsd4_decode_open_claim4()returns a non-seqid-mutating error, the dispatcher short-circuits beforeop_funcruns:nfsd4_proc_compound() opdesc->op_func == nfsd4_open_omfg if (!seqid_mutating_err(ntohl(op->status))) return op->status; /* nfsd4_open() never runs */ opdesc->op_release(&op->u) /* must still release op_pacl/op_dpacl */Before this change
OP_OPENhad no .op_release in nfsd4_ops[], and the release pair lived insidenfsd4_open()at itsout_err: label. On the short-circuit pathnfsd4_open()is never invoked, so bothposix_aclrefs leak on every malformed OPEN compound that carries valid POSIX ACL createhow4 attributes.Add
nfsd4_open_release()and wire it as .op_release forOP_OPEN.posix_acl_release()is NULL-safe, so the single release site covers both the normal path and thenfsd4_open_omfgshort-circuit. Remove the matchingposix_acl_release()pair from nfsd4_open()'sout_err:
label to avoid double-releasing.The compound loop has two encoding branches:
nfsd4_encode_operation()for normal ops, andnfsd4_encode_replay()for v4.0 replayed ops.op_releasewas only called fromnfsd4_encode_operation(), so resources attached toop->uleak on the replay path. Add anop_releasecall to the replay branch as well to ensure cleanup on every path.Fixes 5fc51dfc2eb1 ("NFSD: Add support for XDR decoding POSIX draft ACLs")Signed-off-by Chris Mason <[email protected]>Reviewed-by Chuck Lever <[email protected]>Signed-off-by Jeff Layton <[email protected]>---
Changes in v2:
- Ensure thatop_releaseis called in the v4.0 replay case as well
- Link to v1: https://lore.kernel.org/r/[email protected]--- fs/nfsd/nfs4proc.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-)fs/nfsd/nfs4proc.c +7
-2@@ -681,8 +681,6 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,nfsd4_cleanup_open_state (cstate, open);nfsd4_bump_seqid (cstate, status); out_err: -posix_acl_release (open->op_dpacl); -posix_acl_release (open->op_pacl);return status; }@@ -704,6 +702,13 @@ static __be32 nfsd4_open_omfg(struct svc_rqst *rqstp, struct nfsd4_compound_statreturn nfsd4_open (rqstp, cstate, &op->u); } +static void +nfsd4_open_release (union nfsd4_op_u *u) +{ +posix_acl_release (u->open.op_dpacl); +posix_acl_release (u->open.op_pacl); +} +/* * filehandle-manipulating ops. */ fs/nfsd/nfs4proc.c nfsd4_proc_compound(struct svc_rqst *rqstp) · line 3226
Quoted 8 lines
fs/nfsd/nfs4proc.c +2
-0@@ -3214,6 +3219,8 @@ nfsd4_proc_compound(struct svc_rqst *rqstp) op->replay = &cstate->replay_owner->so_replay;nfsd4_encode_replay (resp->xdr, op); status = op->status = op->replay->rp_status; +if (op->opdesc->op_release) + op->opdesc->op_release (&op->u); }else {nfsd4_encode_operation (resp, op); status = op->status;I think this patch is good, but I think it would be even better if the ->op_release() call were moved out of
nfsd4_encode_operation()and places after this if-else. Then there would be only one call-site in a fairly obviously-correct place.
But:
Quoted 6 lines
Reviewed-by NeilBrown <[email protected]>for if you just want to stick with this version.
Thanks,
NeilBrown
I like that idea.
I'll be testing a pile of other patches today anyway, so I'll make this change and test it alongside the rest.
Chuck, you can either take this one and I'll do a cleanup patch along the lines of what Neil suggests, or I can send a v3.
Quoted 19 lines
Quoted 19 lines
fs/nfsd/nfs4proc.c +1
-1@@ -3718,6 +3725,7 @@ static const struct nfsd4_operation nfsd4_ops[] = { }, [OP_OPEN] = { .op_func = nfsd4_open, + .op_release = nfsd4_open_release, .op_flags = OP_HANDLES_WRONGSEC | OP_MODIFIES_SOMETHING, .op_name = "OP_OPEN", .op_rsize_bop = nfsd4_open_rsize, ---base-commit:
6c0004650ba248a12937ada16f9ba961b35ce2b5
change-id: 20260531-nfsd-testing-9122bf51ce95Best regards,
Signature · 1 line
Jeff Layton <[email protected]>
Signature · 1 line
Jeff Layton <[email protected]>
Quoted 14 lines · Jeff Layton
Quoted 11 lines · NeilBrown
I think this patch is good, but I think it would be even better if the ->op_release() call were moved out of
nfsd4_encode_operation()and places after this if-else. Then there would be only one call-site in a fairly obviously-correct place.
But:Reviewed-by NeilBrown <[email protected]>for if you just want to stick with this version.
Thanks,
NeilBrown
Quoted 7 lines
I like that idea.
I'll be testing a pile of other patches today anyway, so I'll make this change and test it alongside the rest.
Chuck, you can either take this one and I'll do a cleanup patch along the lines of what Neil suggests, or I can send a v3.
v3 sounds fine.
Signature · 1 line
Chuck Lever