Re: [PATCH 06/13] NFSD: add posix ACLs to struct nfsd_attrs

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 




> On Jul 26, 2022, at 2:45 AM, NeilBrown <neilb@xxxxxxx> wrote:
> 
> pacl and dpacl pointers are added to struct nfsd_attrs, which requires
> that we have an nfsd_attrs_free() function to free them.
> Those nfsv4 functions that can set ACLs now set up these pointers
> based on the passed in NFSv4 ACL.
> 
> nfsd_setattr() sets the acls as appropriate.
> 
> Errors are handled as with security labels.
> 
> Signed-off-by: NeilBrown <neilb@xxxxxxx>
> ---
> fs/nfsd/acl.h      |    6 ++++--
> fs/nfsd/nfs4acl.c  |   46 +++++++---------------------------------------
> fs/nfsd/nfs4proc.c |   46 ++++++++++++++++------------------------------
> fs/nfsd/vfs.c      |    8 ++++++++
> fs/nfsd/vfs.h      |   10 ++++++++++
> 5 files changed, 45 insertions(+), 71 deletions(-)
> 
> diff --git a/fs/nfsd/acl.h b/fs/nfsd/acl.h
> index ba14d2f4b64f..4b7324458a94 100644
> --- a/fs/nfsd/acl.h
> +++ b/fs/nfsd/acl.h
> @@ -38,6 +38,8 @@
> struct nfs4_acl;
> struct svc_fh;
> struct svc_rqst;
> +struct nfsd_attrs;
> +enum nfs_ftype4;
> 
> int nfs4_acl_bytes(int entries);
> int nfs4_acl_get_whotype(char *, u32);
> @@ -45,7 +47,7 @@ __be32 nfs4_acl_write_who(struct xdr_stream *xdr, int who);
> 
> int nfsd4_get_nfs4_acl(struct svc_rqst *rqstp, struct dentry *dentry,
> 		struct nfs4_acl **acl);
> -__be32 nfsd4_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp,
> -		struct nfs4_acl *acl);
> +__be32 nfsd4_acl_to_attr(enum nfs_ftype4 type, struct nfs4_acl *acl,
> +			 struct nfsd_attrs *attr);
> 
> #endif /* LINUX_NFS4_ACL_H */
> diff --git a/fs/nfsd/nfs4acl.c b/fs/nfsd/nfs4acl.c
> index eaa3a0cf38f1..8a5b847b6c73 100644
> --- a/fs/nfsd/nfs4acl.c
> +++ b/fs/nfsd/nfs4acl.c
> @@ -751,58 +751,26 @@ static int nfs4_acl_nfsv4_to_posix(struct nfs4_acl *acl,
> 	return ret;
> }
> 
> -__be32
> -nfsd4_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp,
> -		struct nfs4_acl *acl)
> +__be32 nfsd4_acl_to_attr(enum nfs_ftype4 type, struct nfs4_acl *acl,
> +			 struct nfsd_attrs *attr)
> {
> -	__be32 error;
> 	int host_error;
> -	struct dentry *dentry;
> -	struct inode *inode;
> -	struct posix_acl *pacl = NULL, *dpacl = NULL;
> 	unsigned int flags = 0;
> 
> -	/* Get inode */
> -	error = fh_verify(rqstp, fhp, 0, NFSD_MAY_SATTR);
> -	if (error)
> -		return error;
> -
> -	dentry = fhp->fh_dentry;
> -	inode = d_inode(dentry);
> +	if (!acl)
> +		return nfs_ok;
> 
> -	if (S_ISDIR(inode->i_mode))
> +	if (type == NF4DIR)
> 		flags = NFS4_ACL_DIR;
> 
> -	host_error = nfs4_acl_nfsv4_to_posix(acl, &pacl, &dpacl, flags);
> +	host_error = nfs4_acl_nfsv4_to_posix(acl, &attr->pacl, &attr->dpacl,
> +					     flags);
> 	if (host_error == -EINVAL)
> 		return nfserr_attrnotsupp;
> -	if (host_error < 0)
> -		goto out_nfserr;
> -
> -	fh_lock(fhp);
> -
> -	host_error = set_posix_acl(&init_user_ns, inode, ACL_TYPE_ACCESS, pacl);
> -	if (host_error < 0)
> -		goto out_drop_lock;
> -
> -	if (S_ISDIR(inode->i_mode)) {
> -		host_error = set_posix_acl(&init_user_ns, inode,
> -					   ACL_TYPE_DEFAULT, dpacl);
> -	}
> -
> -out_drop_lock:
> -	fh_unlock(fhp);
> -
> -	posix_acl_release(pacl);
> -	posix_acl_release(dpacl);
> -out_nfserr:
> -	if (host_error == -EOPNOTSUPP)
> -		return nfserr_attrnotsupp;
> 	else
> 		return nfserrno(host_error);
> }
> 
> -
> static short
> ace2type(struct nfs4_ace *ace)
> {
> diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
> index 83d2b645b0d6..c49cd04cb567 100644
> --- a/fs/nfsd/nfs4proc.c
> +++ b/fs/nfsd/nfs4proc.c
> @@ -128,26 +128,6 @@ is_create_with_attrs(struct nfsd4_open *open)
> 		    || open->op_createmode == NFS4_CREATE_EXCLUSIVE4_1);
> }
> 
> -/*
> - * if error occurs when setting the acl, just clear the acl bit
> - * in the returned attr bitmap.
> - */
> -static void
> -do_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp,
> -		struct nfs4_acl *acl, u32 *bmval)
> -{
> -	__be32 status;
> -
> -	status = nfsd4_set_nfs4_acl(rqstp, fhp, acl);
> -	if (status)
> -		/*
> -		 * We should probably fail the whole open at this point,
> -		 * but we've already created the file, so it's too late;
> -		 * So this seems the least of evils:
> -		 */
> -		bmval[0] &= ~FATTR4_WORD0_ACL;
> -}
> -
> static inline void
> fh_dup2(struct svc_fh *dst, struct svc_fh *src)
> {
> @@ -281,6 +261,9 @@ nfsd4_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp,
> 	if (host_err)
> 		return nfserrno(host_err);
> 
> +	if (is_create_with_attrs(open))
> +		nfsd4_acl_to_attr(NF4REG, open->op_acl, &attrs);
> +
> 	fh_lock_nested(fhp, I_MUTEX_PARENT);
> 
> 	child = lookup_one_len(open->op_fname, parent, open->op_fnamelen);
> @@ -382,8 +365,11 @@ nfsd4_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp,
> 
> 	if (attrs.label_failed)
> 		open->op_bmval[2] &= ~FATTR4_WORD2_SECURITY_LABEL;
> +	if (attrs.acl_failed)
> +		open->op_bmval[0] &= ~FATTR4_WORD0_ACL;
> out:
> 	fh_unlock(fhp);
> +	nfsd_attrs_free(&attrs);
> 	if (child && !IS_ERR(child))
> 		dput(child);
> 	fh_drop_write(fhp);
> @@ -446,9 +432,6 @@ do_open_lookup(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, stru
> 	if (status)
> 		goto out;
> 
> -	if (is_create_with_attrs(open) && open->op_acl != NULL)
> -		do_set_nfs4_acl(rqstp, *resfh, open->op_acl, open->op_bmval);
> -
> 	nfsd4_set_open_owner_reply_cache(cstate, open, *resfh);
> 	accmode = NFSD_MAY_NOP;
> 	if (open->op_created ||
> @@ -779,6 +762,7 @@ nfsd4_create(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
> 	if (status)
> 		return status;
> 
> +	status = nfsd4_acl_to_attr(create->cr_type, create->cr_acl, &attrs);
> 	current->fs->umask = create->cr_umask;
> 	switch (create->cr_type) {
> 	case NF4LNK:
> @@ -837,10 +821,8 @@ nfsd4_create(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
> 
> 	if (attrs.label_failed)
> 		create->cr_bmval[2] &= ~FATTR4_WORD2_SECURITY_LABEL;
> -
> -	if (create->cr_acl != NULL)
> -		do_set_nfs4_acl(rqstp, &resfh, create->cr_acl,
> -				create->cr_bmval);
> +	if (attrs.label_failed)
> +		create->cr_bmval[0] &= ~FATTR4_WORD0_ACL;

I think this needs to be "if (attrs.acl_failed)". I've fixed this
in my tree.


> 	fh_unlock(&cstate->current_fh);
> 	set_change_info(&create->cr_cinfo, &cstate->current_fh);
> @@ -849,6 +831,7 @@ nfsd4_create(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
> 	fh_put(&resfh);
> out_umask:
> 	current->fs->umask = 0;
> +	nfsd_attrs_free(&attrs);
> 	return status;
> }
> 
> @@ -1123,6 +1106,7 @@ nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
> 		.iattr = &setattr->sa_iattr,
> 		.label = &setattr->sa_label,
> 	};
> +	struct inode *inode;
> 	__be32 status = nfs_ok;
> 	int err;
> 
> @@ -1145,9 +1129,10 @@ nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
> 	if (status)
> 		goto out;
> 
> -	if (setattr->sa_acl != NULL)
> -		status = nfsd4_set_nfs4_acl(rqstp, &cstate->current_fh,
> -					    setattr->sa_acl);
> +	inode = cstate->current_fh.fh_dentry->d_inode;
> +	status = nfsd4_acl_to_attr(S_ISDIR(inode->i_mode) ? NF4DIR : NF4REG,
> +				   setattr->sa_acl, &attrs);
> +
> 	if (status)
> 		goto out;
> 	status = nfsd_setattr(rqstp, &cstate->current_fh, &attrs,
> @@ -1155,6 +1140,7 @@ nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
> 	if (!status)
> 		status = attrs.label_failed;
> out:
> +	nfsd_attrs_free(&attrs);
> 	fh_drop_write(&cstate->current_fh);
> 	return status;
> }
> diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
> index e7a18bedf499..4bb05586a258 100644
> --- a/fs/nfsd/vfs.c
> +++ b/fs/nfsd/vfs.c
> @@ -461,6 +461,14 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp,
> 	if (attr->label && attr->label->len)
> 		attr->label_failed = security_inode_setsecctx(
> 			dentry, attr->label->data, attr->label->len);
> +	if (attr->pacl)
> +		attr->acl_failed = set_posix_acl(&init_user_ns,
> +						 inode, ACL_TYPE_ACCESS,
> +						 attr->pacl);
> +	if (!attr->acl_failed && attr->dpacl && S_ISDIR(inode->i_mode))
> +		attr->acl_failed = set_posix_acl(&init_user_ns,
> +						 inode, ACL_TYPE_DEFAULT,
> +						 attr->dpacl);
> 	fh_unlock(fhp);
> 	if (size_change)
> 		put_write_access(inode);
> diff --git a/fs/nfsd/vfs.h b/fs/nfsd/vfs.h
> index 8464e04af1ea..9343aac0bd15 100644
> --- a/fs/nfsd/vfs.h
> +++ b/fs/nfsd/vfs.h
> @@ -6,6 +6,8 @@
> #ifndef LINUX_NFSD_VFS_H
> #define LINUX_NFSD_VFS_H
> 
> +#include <linux/fs.h>
> +#include <linux/posix_acl.h>
> #include "nfsfh.h"
> #include "nfsd.h"
> 
> @@ -45,9 +47,17 @@ typedef int (*nfsd_filldir_t)(void *, const char *, int, loff_t, u64, unsigned);
> struct nfsd_attrs {
> 	struct iattr *iattr;
> 	struct xdr_netobj *label;
> +	struct posix_acl *pacl, *dpacl;
> 	int label_failed;
> +	int acl_failed;
> };
> 
> +static inline void nfsd_attrs_free(struct nfsd_attrs *attrs)
> +{
> +	posix_acl_release(attrs->pacl);
> +	posix_acl_release(attrs->dpacl);
> +}
> +
> int		nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry **dpp,
> 		                struct svc_export **expp);
> __be32		nfsd_lookup(struct svc_rqst *, struct svc_fh *,
> 
> 

--
Chuck Lever







[Index of Archives]     [Linux Filesystem Development]     [Linux USB Development]     [Linux Media Development]     [Video for Linux]     [Linux NILFS]     [Linux Audio Users]     [Yosemite Info]     [Linux SCSI]

  Powered by Linux