NFSD: add posix ACLs to struct nfsd_attrs
authorNeilBrown <neilb@suse.de>
Tue, 26 Jul 2022 06:45:30 +0000 (16:45 +1000)
committerChuck Lever <chuck.lever@oracle.com>
Thu, 4 Aug 2022 14:28:03 +0000 (10:28 -0400)
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@suse.de>
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
fs/nfsd/acl.h
fs/nfsd/nfs4acl.c
fs/nfsd/nfs4proc.c
fs/nfsd/vfs.c
fs/nfsd/vfs.h

index ba14d2f4b64f4b71aeb9c3160a2d84db3e5aab48..4b7324458a94e13de4785ac7866932967ffb1b51 100644 (file)
@@ -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 */
index eaa3a0cf38f1453c97c08f4ed3a59c3bbfaabfe1..bb8e2f6d7d03c4b9b8f8abeeae7d6e6019c6fadf 100644 (file)
@@ -751,58 +751,26 @@ out_estate:
        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->na_pacl,
+                                            &attr->na_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)
 {
index bc7ab271524df5fb6e83dfa5ce6ccc58d905ab9d..ade2ea29feb06fd9288640f4fb2746dfaf6cb17c 100644 (file)
@@ -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 @@ set_attr:
 
        if (attrs.na_labelerr)
                open->op_bmval[2] &= ~FATTR4_WORD2_SECURITY_LABEL;
+       if (attrs.na_aclerr)
+               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.na_labelerr)
                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.na_aclerr)
+               create->cr_bmval[0] &= ~FATTR4_WORD0_ACL;
 
        fh_unlock(&cstate->current_fh);
        set_change_info(&create->cr_cinfo, &cstate->current_fh);
@@ -849,6 +831,7 @@ out:
        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,
                .na_iattr       = &setattr->sa_iattr,
                .na_seclabel    = &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 = nfserrno(attrs.na_labelerr);
 out:
+       nfsd_attrs_free(&attrs);
        fh_drop_write(&cstate->current_fh);
        return status;
 }
index e9e1d5cd6ffbe5f29e6e42f20b3576750d8ce804..fdea5cce2b228221abad64d188b04689d3ca7788 100644 (file)
@@ -461,6 +461,15 @@ out_unlock:
        if (attr->na_seclabel && attr->na_seclabel->len)
                attr->na_labelerr = security_inode_setsecctx(dentry,
                        attr->na_seclabel->data, attr->na_seclabel->len);
+       if (IS_ENABLED(CONFIG_FS_POSIX_ACL) && attr->na_pacl)
+               attr->na_aclerr = set_posix_acl(&init_user_ns,
+                                               inode, ACL_TYPE_ACCESS,
+                                               attr->na_pacl);
+       if (IS_ENABLED(CONFIG_FS_POSIX_ACL) &&
+           !attr->na_aclerr && attr->na_dpacl && S_ISDIR(inode->i_mode))
+               attr->na_aclerr = set_posix_acl(&init_user_ns,
+                                               inode, ACL_TYPE_DEFAULT,
+                                               attr->na_dpacl);
        fh_unlock(fhp);
        if (size_change)
                put_write_access(inode);
index d5d4cfe37c9339536771e816f02d8638c370b9e4..c95cd414b4bb01d0db40235fbf1eb36c7e14813f 100644 (file)
@@ -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,10 +47,19 @@ typedef int (*nfsd_filldir_t)(void *, const char *, int, loff_t, u64, unsigned);
 struct nfsd_attrs {
        struct iattr            *na_iattr;      /* input */
        struct xdr_netobj       *na_seclabel;   /* input */
+       struct posix_acl        *na_pacl;       /* input */
+       struct posix_acl        *na_dpacl;      /* input */
 
        int                     na_labelerr;    /* output */
+       int                     na_aclerr;      /* output */
 };
 
+static inline void nfsd_attrs_free(struct nfsd_attrs *attrs)
+{
+       posix_acl_release(attrs->na_pacl);
+       posix_acl_release(attrs->na_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 *,