diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 72edf4add536..d476d108f6e1 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -1214,6 +1214,8 @@ nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd_attrs attrs = { .na_iattr = &setattr->sa_iattr, .na_seclabel = &setattr->sa_label, + .na_pacl = setattr->sa_pacl, + .na_dpacl = setattr->sa_dpacl, }; bool save_no_wcc, deleg_attrs; struct nfs4_stid *st = NULL; @@ -1221,6 +1223,10 @@ nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, __be32 status = nfs_ok; int err; + /* Transfer ownership to attrs for cleanup via nfsd_attrs_free() */ + setattr->sa_pacl = NULL; + setattr->sa_dpacl = NULL; + deleg_attrs = setattr->sa_bmval[2] & (FATTR4_WORD2_TIME_DELEG_ACCESS | FATTR4_WORD2_TIME_DELEG_MODIFY); @@ -1234,7 +1240,7 @@ nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, &cstate->current_fh, &setattr->sa_stateid, flags, NULL, &st); if (status) - return status; + goto out_err; } if (deleg_attrs) { @@ -1252,17 +1258,24 @@ nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, if (st) nfs4_put_stid(st); if (status) - return status; + goto out_err; err = fh_want_write(&cstate->current_fh); - if (err) - return nfserrno(err); + if (err) { + status = nfserrno(err); + goto out_err; + } status = nfs_ok; status = check_attr_support(cstate, setattr->sa_bmval, nfsd_attrmask); if (status) goto out; + if (setattr->sa_acl && (attrs.na_dpacl || attrs.na_pacl)) { + status = nfserr_inval; + goto out; + } + inode = cstate->current_fh.fh_dentry->d_inode; status = nfsd4_acl_to_attr(S_ISDIR(inode->i_mode) ? NF4DIR : NF4REG, setattr->sa_acl, &attrs); @@ -1280,8 +1293,9 @@ nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, if (!status) status = nfserrno(attrs.na_paclerr); out: - nfsd_attrs_free(&attrs); fh_drop_write(&cstate->current_fh); +out_err: + nfsd_attrs_free(&attrs); return status; }