Commit 4b2ca38a authored by J. Bruce Fields's avatar J. Bruce Fields Committed by Linus Torvalds

knfsd: nfsd4: fix handling of acl errrors

nfs4_acl_nfsv4_to_posix() returns an error and returns any posix acls
calculated in two caller-provided pointers.  It was setting these pointers to
-errno in some error cases, resulting in nfsd4_set_nfs4_acl() calling
posix_acl_release() with a -errno as an argument.

Fix both the caller and the callee, by modifying nfsd4_set_nfs4_acl() to
stop relying on the passed-in-pointers being left as NULL in the error
case, and by modifying nfs4_acl_nfsv4_to_posix() to stop returning
garbage in those pointers.

Thanks to Alex Soule for reporting the bug.
Signed-off-by: default avatar"J. Bruce Fields" <bfields@citi.umich.edu>
Cc: Alexander Soule <soule@umich.edu>
Signed-off-by: default avatarNeil Brown <neilb@suse.de>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 0ac68d17
...@@ -737,13 +737,16 @@ int nfs4_acl_nfsv4_to_posix(struct nfs4_acl *acl, struct posix_acl **pacl, ...@@ -737,13 +737,16 @@ int nfs4_acl_nfsv4_to_posix(struct nfs4_acl *acl, struct posix_acl **pacl,
*pacl = posix_state_to_acl(&effective_acl_state, flags); *pacl = posix_state_to_acl(&effective_acl_state, flags);
if (IS_ERR(*pacl)) { if (IS_ERR(*pacl)) {
ret = PTR_ERR(*pacl); ret = PTR_ERR(*pacl);
*pacl = NULL;
goto out_dstate; goto out_dstate;
} }
*dpacl = posix_state_to_acl(&default_acl_state, *dpacl = posix_state_to_acl(&default_acl_state,
flags | NFS4_ACL_TYPE_DEFAULT); flags | NFS4_ACL_TYPE_DEFAULT);
if (IS_ERR(*dpacl)) { if (IS_ERR(*dpacl)) {
ret = PTR_ERR(*dpacl); ret = PTR_ERR(*dpacl);
*dpacl = NULL;
posix_acl_release(*pacl); posix_acl_release(*pacl);
*pacl = NULL;
goto out_dstate; goto out_dstate;
} }
sort_pacl(*pacl); sort_pacl(*pacl);
......
...@@ -435,7 +435,7 @@ nfsd4_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp, ...@@ -435,7 +435,7 @@ nfsd4_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp,
/* Get inode */ /* Get inode */
error = fh_verify(rqstp, fhp, 0 /* S_IFREG */, MAY_SATTR); error = fh_verify(rqstp, fhp, 0 /* S_IFREG */, MAY_SATTR);
if (error) if (error)
goto out; return error;
dentry = fhp->fh_dentry; dentry = fhp->fh_dentry;
inode = dentry->d_inode; inode = dentry->d_inode;
...@@ -444,33 +444,25 @@ nfsd4_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp, ...@@ -444,33 +444,25 @@ nfsd4_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp,
host_error = nfs4_acl_nfsv4_to_posix(acl, &pacl, &dpacl, flags); host_error = nfs4_acl_nfsv4_to_posix(acl, &pacl, &dpacl, flags);
if (host_error == -EINVAL) { if (host_error == -EINVAL) {
error = nfserr_attrnotsupp; return nfserr_attrnotsupp;
goto out;
} else if (host_error < 0) } else if (host_error < 0)
goto out_nfserr; goto out_nfserr;
host_error = set_nfsv4_acl_one(dentry, pacl, POSIX_ACL_XATTR_ACCESS); host_error = set_nfsv4_acl_one(dentry, pacl, POSIX_ACL_XATTR_ACCESS);
if (host_error < 0) if (host_error < 0)
goto out_nfserr; goto out_release;
if (S_ISDIR(inode->i_mode)) { if (S_ISDIR(inode->i_mode))
host_error = set_nfsv4_acl_one(dentry, dpacl, POSIX_ACL_XATTR_DEFAULT); host_error = set_nfsv4_acl_one(dentry, dpacl, POSIX_ACL_XATTR_DEFAULT);
if (host_error < 0)
goto out_nfserr;
}
error = nfs_ok;
out: out_release:
posix_acl_release(pacl); posix_acl_release(pacl);
posix_acl_release(dpacl); posix_acl_release(dpacl);
return (error);
out_nfserr: out_nfserr:
if (host_error == -EOPNOTSUPP) if (host_error == -EOPNOTSUPP)
error = nfserr_attrnotsupp; return nfserr_attrnotsupp;
else else
error = nfserrno(host_error); return nfserrno(host_error);
goto out;
} }
static struct posix_acl * static struct posix_acl *
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment