* [PATCH 000 of 9] knfsd: minor gss/v4 cleanups and major ACL surgery.
@ 2006-09-04 23:15 NeilBrown
2006-09-04 23:15 ` [PATCH 001 of 9] knfsd: svcrpc: gss: factor out some common wrapping code NeilBrown
` (8 more replies)
0 siblings, 9 replies; 10+ messages in thread
From: NeilBrown @ 2006-09-04 23:15 UTC (permalink / raw)
To: Andrew Morton; +Cc: nfs, linux-kernel
Following are 9 patches for nfsd from Bruce Fields. First 5 are minor
cleanups around gss code and elsewhere. Last 4 make substantial
changes to ACL handling, particularly for mapping between Posix draft
ACLs and NFSv4 ACLs.
Thanks,
NeilBrown
[PATCH 001 of 9] knfsd: svcrpc: gss: factor out some common wrapping code
[PATCH 002 of 9] knfsd: svcrpc: gss: fix failure on SVC_DENIED in integrity case
[PATCH 003 of 9] knfsd: svcrpc: use consistent variable name for the reply state
[PATCH 004 of 9] knfsd: nfsd4: refactor exp_pseudoroot
[PATCH 005 of 9] knfsd: nfsd4: clean up exp_pseudoroot
[PATCH 006 of 9] knfsd: nfsd4: acls: relax the nfsv4->posix mapping
[PATCH 007 of 9] knfsd: nfsd4: acls: fix inheritance
[PATCH 008 of 9] knfsd: nfsd4: acls: simplify nfs4_acl_nfsv4_to_posix interface
[PATCH 009 of 9] knfsd: nfsd4: acls: fix handling of zero-length acls
^ permalink raw reply [flat|nested] 10+ messages in thread* [PATCH 001 of 9] knfsd: svcrpc: gss: factor out some common wrapping code 2006-09-04 23:15 [PATCH 000 of 9] knfsd: minor gss/v4 cleanups and major ACL surgery NeilBrown @ 2006-09-04 23:15 ` NeilBrown 2006-09-04 23:15 ` [PATCH 002 of 9] knfsd: svcrpc: gss: fix failure on SVC_DENIED in integrity case NeilBrown ` (7 subsequent siblings) 8 siblings, 0 replies; 10+ messages in thread From: NeilBrown @ 2006-09-04 23:15 UTC (permalink / raw) To: Andrew Morton; +Cc: nfs, linux-kernel From: J.Bruce Fields <bfields@fieldses.org> Factor out some common code from the integrity and privacy cases. Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu> Signed-off-by: Neil Brown <neilb@suse.de> ### Diffstat output ./net/sunrpc/auth_gss/svcauth_gss.c | 43 +++++++++++++++++++----------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff .prev/net/sunrpc/auth_gss/svcauth_gss.c ./net/sunrpc/auth_gss/svcauth_gss.c --- .prev/net/sunrpc/auth_gss/svcauth_gss.c 2006-09-04 17:09:50.000000000 +1000 +++ ./net/sunrpc/auth_gss/svcauth_gss.c 2006-09-04 17:12:31.000000000 +1000 @@ -1147,6 +1147,25 @@ out: return ret; } +u32 * +svcauth_gss_prepare_to_wrap(struct xdr_buf *resbuf, struct gss_svc_data *gsd) +{ + u32 *p; + + p = gsd->body_start; + gsd->body_start = NULL; + /* move accept_stat to right place: */ + memcpy(p, p + 2, 4); + /* Don't wrap in failure case: */ + /* Counting on not getting here if call was not even accepted! */ + if (*p != rpc_success) { + resbuf->head[0].iov_len -= 2 * 4; + return NULL; + } + p++; + return p; +} + static inline int svcauth_gss_wrap_resp_integ(struct svc_rqst *rqstp) { @@ -1160,17 +1179,9 @@ svcauth_gss_wrap_resp_integ(struct svc_r int integ_offset, integ_len; int stat = -EINVAL; - p = gsd->body_start; - gsd->body_start = NULL; - /* move accept_stat to right place: */ - memcpy(p, p + 2, 4); - /* Don't wrap in failure case: */ - /* Counting on not getting here if call was not even accepted! */ - if (*p != rpc_success) { - resbuf->head[0].iov_len -= 2 * 4; + p = svcauth_gss_prepare_to_wrap(resbuf, gsd); + if (p == NULL) goto out; - } - p++; integ_offset = (u8 *)(p + 1) - (u8 *)resbuf->head[0].iov_base; integ_len = resbuf->len - integ_offset; BUG_ON(integ_len % 4); @@ -1222,17 +1233,9 @@ svcauth_gss_wrap_resp_priv(struct svc_rq int offset, *len; int pad; - p = gsd->body_start; - gsd->body_start = NULL; - /* move accept_stat to right place: */ - memcpy(p, p + 2, 4); - /* Don't wrap in failure case: */ - /* Counting on not getting here if call was not even accepted! */ - if (*p != rpc_success) { - resbuf->head[0].iov_len -= 2 * 4; + p = svcauth_gss_prepare_to_wrap(resbuf, gsd); + if (p == NULL) return 0; - } - p++; len = p++; offset = (u8 *)p - (u8 *)resbuf->head[0].iov_base; *p++ = htonl(gc->gc_seq); ^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH 002 of 9] knfsd: svcrpc: gss: fix failure on SVC_DENIED in integrity case 2006-09-04 23:15 [PATCH 000 of 9] knfsd: minor gss/v4 cleanups and major ACL surgery NeilBrown 2006-09-04 23:15 ` [PATCH 001 of 9] knfsd: svcrpc: gss: factor out some common wrapping code NeilBrown @ 2006-09-04 23:15 ` NeilBrown 2006-09-04 23:15 ` [PATCH 003 of 9] knfsd: svcrpc: use consistent variable name for the reply state NeilBrown ` (6 subsequent siblings) 8 siblings, 0 replies; 10+ messages in thread From: NeilBrown @ 2006-09-04 23:15 UTC (permalink / raw) To: Andrew Morton; +Cc: nfs, linux-kernel From: J.Bruce Fields <bfields@fieldses.org> If the request is denied after gss_accept was called, we shouldn't try to wrap the reply. We were checking the accept_stat but not the reply_stat. To check the reply_stat in _release, we need a pointer to before (rather than after) the verifier, so modify body_start appropriately. Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu> Signed-off-by: Neil Brown <neilb@suse.de> ### Diffstat output ./net/sunrpc/auth_gss/svcauth_gss.c | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff .prev/net/sunrpc/auth_gss/svcauth_gss.c ./net/sunrpc/auth_gss/svcauth_gss.c --- .prev/net/sunrpc/auth_gss/svcauth_gss.c 2006-09-04 17:12:31.000000000 +1000 +++ ./net/sunrpc/auth_gss/svcauth_gss.c 2006-09-04 17:13:17.000000000 +1000 @@ -903,9 +903,9 @@ out_seq: struct gss_svc_data { /* decoded gss client cred: */ struct rpc_gss_wire_cred clcred; - /* pointer to the beginning of the procedure-specific results, - * which may be encrypted/checksummed in svcauth_gss_release: */ - u32 *body_start; + /* save a pointer to the beginning of the encoded verifier, + * for use in encryption/checksumming in svcauth_gss_release: */ + u32 *verf_start; struct rsc *rsci; }; @@ -968,7 +968,7 @@ svcauth_gss_accept(struct svc_rqst *rqst if (!svcdata) goto auth_err; rqstp->rq_auth_data = svcdata; - svcdata->body_start = NULL; + svcdata->verf_start = NULL; svcdata->rsci = NULL; gc = &svcdata->clcred; @@ -1097,6 +1097,7 @@ svcauth_gss_accept(struct svc_rqst *rqst goto complete; case RPC_GSS_PROC_DATA: *authp = rpcsec_gsserr_ctxproblem; + svcdata->verf_start = resv->iov_base + resv->iov_len; if (gss_write_verf(rqstp, rsci->mechctx, gc->gc_seq)) goto auth_err; rqstp->rq_cred = rsci->cred; @@ -1110,7 +1111,6 @@ svcauth_gss_accept(struct svc_rqst *rqst gc->gc_seq, rsci->mechctx)) goto auth_err; /* placeholders for length and seq. number: */ - svcdata->body_start = resv->iov_base + resv->iov_len; svc_putu32(resv, 0); svc_putu32(resv, 0); break; @@ -1119,7 +1119,6 @@ svcauth_gss_accept(struct svc_rqst *rqst gc->gc_seq, rsci->mechctx)) goto auth_err; /* placeholders for length and seq. number: */ - svcdata->body_start = resv->iov_base + resv->iov_len; svc_putu32(resv, 0); svc_putu32(resv, 0); break; @@ -1150,14 +1149,21 @@ out: u32 * svcauth_gss_prepare_to_wrap(struct xdr_buf *resbuf, struct gss_svc_data *gsd) { - u32 *p; + u32 *p, verf_len; + + p = gsd->verf_start; + gsd->verf_start = NULL; - p = gsd->body_start; - gsd->body_start = NULL; + /* If the reply stat is nonzero, don't wrap: */ + if (*(p-1) != rpc_success) + return NULL; + /* Skip the verifier: */ + p += 1; + verf_len = ntohl(*p++); + p += XDR_QUADLEN(verf_len); /* move accept_stat to right place: */ memcpy(p, p + 2, 4); - /* Don't wrap in failure case: */ - /* Counting on not getting here if call was not even accepted! */ + /* Also don't wrap if the accept stat is nonzero: */ if (*p != rpc_success) { resbuf->head[0].iov_len -= 2 * 4; return NULL; @@ -1283,7 +1289,7 @@ svcauth_gss_release(struct svc_rqst *rqs if (gc->gc_proc != RPC_GSS_PROC_DATA) goto out; /* Release can be called twice, but we only wrap once. */ - if (gsd->body_start == NULL) + if (gsd->verf_start == NULL) goto out; /* normally not set till svc_send, but we need it here: */ /* XXX: what for? Do we mess it up the moment we call svc_putu32 ^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH 003 of 9] knfsd: svcrpc: use consistent variable name for the reply state 2006-09-04 23:15 [PATCH 000 of 9] knfsd: minor gss/v4 cleanups and major ACL surgery NeilBrown 2006-09-04 23:15 ` [PATCH 001 of 9] knfsd: svcrpc: gss: factor out some common wrapping code NeilBrown 2006-09-04 23:15 ` [PATCH 002 of 9] knfsd: svcrpc: gss: fix failure on SVC_DENIED in integrity case NeilBrown @ 2006-09-04 23:15 ` NeilBrown 2006-09-04 23:15 ` [PATCH 004 of 9] knfsd: nfsd4: refactor exp_pseudoroot NeilBrown ` (5 subsequent siblings) 8 siblings, 0 replies; 10+ messages in thread From: NeilBrown @ 2006-09-04 23:15 UTC (permalink / raw) To: Andrew Morton; +Cc: nfs, linux-kernel From: J.Bruce Fields <bfields@fieldses.org> The rpc reply has multiple levels of error returns. The code here contributes to the confusion by using "accept_statp" for a pointer to what the rfc (and wireshark, etc.) refer to as the "reply_stat". (The confusion is compounded by the fact that the rfc also has an "accept_stat" which follows the reply_stat in the succesful case.) Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu> Signed-off-by: Neil Brown <neilb@suse.de> ### Diffstat output ./net/sunrpc/svc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff .prev/net/sunrpc/svc.c ./net/sunrpc/svc.c --- .prev/net/sunrpc/svc.c 2006-09-04 17:09:50.000000000 +1000 +++ ./net/sunrpc/svc.c 2006-09-04 17:15:35.000000000 +1000 @@ -699,7 +699,7 @@ svc_process(struct svc_rqst *rqstp) u32 dir, prog, vers, proc, auth_stat, rpc_stat; int auth_res; - u32 *accept_statp; + u32 *reply_statp; rpc_stat = rpc_success; @@ -740,7 +740,7 @@ svc_process(struct svc_rqst *rqstp) goto err_bad_rpc; /* Save position in case we later decide to reject: */ - accept_statp = resv->iov_base + resv->iov_len; + reply_statp = resv->iov_base + resv->iov_len; svc_putu32(resv, xdr_zero); /* ACCEPT */ @@ -888,7 +888,7 @@ err_bad_auth: dprintk("svc: authentication failed (%d)\n", ntohl(auth_stat)); serv->sv_stats->rpcbadauth++; /* Restore write pointer to location of accept status: */ - xdr_ressize_check(rqstp, accept_statp); + xdr_ressize_check(rqstp, reply_statp); svc_putu32(resv, xdr_one); /* REJECT */ svc_putu32(resv, xdr_one); /* AUTH_ERROR */ svc_putu32(resv, auth_stat); /* status */ ^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH 004 of 9] knfsd: nfsd4: refactor exp_pseudoroot 2006-09-04 23:15 [PATCH 000 of 9] knfsd: minor gss/v4 cleanups and major ACL surgery NeilBrown ` (2 preceding siblings ...) 2006-09-04 23:15 ` [PATCH 003 of 9] knfsd: svcrpc: use consistent variable name for the reply state NeilBrown @ 2006-09-04 23:15 ` NeilBrown 2006-09-04 23:15 ` [PATCH 005 of 9] knfsd: nfsd4: clean up exp_pseudoroot NeilBrown ` (4 subsequent siblings) 8 siblings, 0 replies; 10+ messages in thread From: NeilBrown @ 2006-09-04 23:15 UTC (permalink / raw) To: Andrew Morton; +Cc: nfs, linux-kernel From: J.Bruce Fields <bfields@fieldses.org> We could be using more common code in exp_pseudoroot(). This will also simplify some changes we need to make later. Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu> Signed-off-by: Neil Brown <neilb@suse.de> ### Diffstat output ./fs/nfsd/export.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff .prev/fs/nfsd/export.c ./fs/nfsd/export.c --- .prev/fs/nfsd/export.c 2006-09-04 17:09:49.000000000 +1000 +++ ./fs/nfsd/export.c 2006-09-04 17:18:25.000000000 +1000 @@ -1048,30 +1048,24 @@ int exp_pseudoroot(struct auth_domain *clp, struct svc_fh *fhp, struct cache_req *creq) { - struct svc_expkey *fsid_key; struct svc_export *exp; int rv; u32 fsidv[2]; mk_fsid_v1(fsidv, 0); - fsid_key = exp_find_key(clp, 1, fsidv, creq); - if (IS_ERR(fsid_key) && PTR_ERR(fsid_key) == -EAGAIN) + exp = exp_find(clp, 1, fsidv, creq); + if (IS_ERR(exp) && PTR_ERR(exp) == -EAGAIN) return nfserr_dropit; - if (!fsid_key || IS_ERR(fsid_key)) - return nfserr_perm; - - exp = exp_get_by_name(clp, fsid_key->ek_mnt, fsid_key->ek_dentry, creq); if (exp == NULL) rv = nfserr_perm; else if (IS_ERR(exp)) rv = nfserrno(PTR_ERR(exp)); else { rv = fh_compose(fhp, exp, - fsid_key->ek_dentry, NULL); + exp->ex_dentry, NULL); exp_put(exp); } - cache_put(&fsid_key->h, &svc_expkey_cache); return rv; } ^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH 005 of 9] knfsd: nfsd4: clean up exp_pseudoroot 2006-09-04 23:15 [PATCH 000 of 9] knfsd: minor gss/v4 cleanups and major ACL surgery NeilBrown ` (3 preceding siblings ...) 2006-09-04 23:15 ` [PATCH 004 of 9] knfsd: nfsd4: refactor exp_pseudoroot NeilBrown @ 2006-09-04 23:15 ` NeilBrown 2006-09-04 23:15 ` [PATCH 006 of 9] knfsd: nfsd4: acls: relax the nfsv4->posix mapping NeilBrown ` (3 subsequent siblings) 8 siblings, 0 replies; 10+ messages in thread From: NeilBrown @ 2006-09-04 23:15 UTC (permalink / raw) To: Andrew Morton; +Cc: nfs, linux-kernel From: J.Bruce Fields <bfields@fieldses.org> The previous patch enables some minor simplification here. Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu> Signed-off-by: Neil Brown <neilb@suse.de> ### Diffstat output ./fs/nfsd/export.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff .prev/fs/nfsd/export.c ./fs/nfsd/export.c --- .prev/fs/nfsd/export.c 2006-09-04 17:18:25.000000000 +1000 +++ ./fs/nfsd/export.c 2006-09-04 17:20:22.000000000 +1000 @@ -1058,14 +1058,11 @@ exp_pseudoroot(struct auth_domain *clp, if (IS_ERR(exp) && PTR_ERR(exp) == -EAGAIN) return nfserr_dropit; if (exp == NULL) - rv = nfserr_perm; + return nfserr_perm; else if (IS_ERR(exp)) - rv = nfserrno(PTR_ERR(exp)); - else { - rv = fh_compose(fhp, exp, - exp->ex_dentry, NULL); - exp_put(exp); - } + return nfserrno(PTR_ERR(exp)); + rv = fh_compose(fhp, exp, exp->ex_dentry, NULL); + exp_put(exp); return rv; } ^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH 006 of 9] knfsd: nfsd4: acls: relax the nfsv4->posix mapping 2006-09-04 23:15 [PATCH 000 of 9] knfsd: minor gss/v4 cleanups and major ACL surgery NeilBrown ` (4 preceding siblings ...) 2006-09-04 23:15 ` [PATCH 005 of 9] knfsd: nfsd4: clean up exp_pseudoroot NeilBrown @ 2006-09-04 23:15 ` NeilBrown 2006-09-04 23:15 ` [PATCH 007 of 9] knfsd: nfsd4: acls: fix inheritance NeilBrown ` (2 subsequent siblings) 8 siblings, 0 replies; 10+ messages in thread From: NeilBrown @ 2006-09-04 23:15 UTC (permalink / raw) To: Andrew Morton; +Cc: nfs, linux-kernel From: J.Bruce Fields <bfields@fieldses.org> Use a different nfsv4->(draft posix) acl mapping which is 1. completely backwards compatible, 2. accepts any nfsv4 acl, and 3. errs on the side of restricting permissions. In detail: 1. completely backwards compatible: The new mapping produces the same result on any acl produced by the existing (draft posix)->nfsv4 mapping; the one exception is that we no longer attempt to guess the value of the mask by assuming certain denies represent the mask. Since the server still keeps track of the mask locally, sequences of chmod's will still be handled fine; the only thing this will change is sequences of chmod's with intervening read-modify-writes of the acl. That last case just isn't worth the trouble and the possible misrepresentations of the user's intent (if we guess that a certain deny indicates masking is in effect when it really isn't). 2. accepts any nfsv4 acl: That's not quite true: we still reject acls that use combinations of inheritance flags that we don't support. We also reject acls that attempt to explicitly deny read_acl or read_attributes permissions, or that attempt to deny write_acl or write_attributes permissions to the owner of the file. 3. errs on the side of restricting permissions: one exception to this last rule: we totally ignore some bits (write_owner, synchronize, read_named_attributes, etc.) that are completely alien to our filesystem semantics, in some cases even if that would mean ignoring an explicit deny that we have no intention of enforcing. Excepting that, the posix acl produced should be the most permissive acl that is not more permissive than the given nfsv4 acl. And the new code's shorter, too. Neato. Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu> Signed-off-by: Neil Brown <neilb@suse.de> ### Diffstat output ./fs/nfsd/nfs4acl.c | 639 ++++++++++++++++++++++------------------------------ 1 file changed, 279 insertions(+), 360 deletions(-) diff .prev/fs/nfsd/nfs4acl.c ./fs/nfsd/nfs4acl.c --- .prev/fs/nfsd/nfs4acl.c 2006-09-04 17:09:48.000000000 +1000 +++ ./fs/nfsd/nfs4acl.c 2006-09-04 17:20:49.000000000 +1000 @@ -96,24 +96,26 @@ deny_mask(u32 allow_mask, unsigned int f /* XXX: modify functions to return NFS errors; they're only ever * used by nfs code, after all.... */ -static int -mode_from_nfs4(u32 perm, unsigned short *mode, unsigned int flags) +/* We only map from NFSv4 to POSIX ACLs when setting ACLs, when we err on the + * side of being more restrictive, so the mode bit mapping below is + * pessimistic. An optimistic version would be needed to handle DENY's, + * but we espect to coalesce all ALLOWs and DENYs before mapping to mode + * bits. */ + +static void +low_mode_from_nfs4(u32 perm, unsigned short *mode, unsigned int flags) { - u32 ignore = 0; + u32 write_mode = NFS4_WRITE_MODE; - if (!(flags & NFS4_ACL_DIR)) - ignore |= NFS4_ACE_DELETE_CHILD; /* ignore it */ - perm |= ignore; + if (flags & NFS4_ACL_DIR) + write_mode |= NFS4_ACE_DELETE_CHILD; *mode = 0; if ((perm & NFS4_READ_MODE) == NFS4_READ_MODE) *mode |= ACL_READ; - if ((perm & NFS4_WRITE_MODE) == NFS4_WRITE_MODE) + if ((perm & write_mode) == write_mode) *mode |= ACL_WRITE; if ((perm & NFS4_EXECUTE_MODE) == NFS4_EXECUTE_MODE) *mode |= ACL_EXECUTE; - if (!MASK_EQUAL(perm, ignore|mask_from_posix(*mode, flags))) - return -EINVAL; - return 0; } struct ace_container { @@ -338,38 +340,6 @@ sort_pacl(struct posix_acl *pacl) return; } -static int -write_pace(struct nfs4_ace *ace, struct posix_acl *pacl, - struct posix_acl_entry **pace, short tag, unsigned int flags) -{ - struct posix_acl_entry *this = *pace; - - if (*pace == pacl->a_entries + pacl->a_count) - return -EINVAL; /* fell off the end */ - (*pace)++; - this->e_tag = tag; - if (tag == ACL_USER_OBJ) - flags |= NFS4_ACL_OWNER; - if (mode_from_nfs4(ace->access_mask, &this->e_perm, flags)) - return -EINVAL; - this->e_id = (tag == ACL_USER || tag == ACL_GROUP ? - ace->who : ACL_UNDEFINED_ID); - return 0; -} - -static struct nfs4_ace * -get_next_v4_ace(struct list_head **p, struct list_head *head) -{ - struct nfs4_ace *ace; - - *p = (*p)->next; - if (*p == head) - return NULL; - ace = list_entry(*p, struct nfs4_ace, l_ace); - - return ace; -} - int nfs4_acl_nfsv4_to_posix(struct nfs4_acl *acl, struct posix_acl **pacl, struct posix_acl **dpacl, unsigned int flags) @@ -429,349 +399,311 @@ out: return error; } -static int -same_who(struct nfs4_ace *a, struct nfs4_ace *b) -{ - return a->whotype == b->whotype && - (a->whotype != NFS4_ACL_WHO_NAMED || a->who == b->who); -} - -static int -complementary_ace_pair(struct nfs4_ace *allow, struct nfs4_ace *deny, - unsigned int flags) -{ - int ignore = 0; - if (!(flags & NFS4_ACL_DIR)) - ignore |= NFS4_ACE_DELETE_CHILD; - return MASK_EQUAL(ignore|deny_mask(allow->access_mask, flags), - ignore|deny->access_mask) && - allow->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE && - deny->type == NFS4_ACE_ACCESS_DENIED_ACE_TYPE && - allow->flag == deny->flag && - same_who(allow, deny); -} - -static inline int -user_obj_from_v4(struct nfs4_acl *n4acl, struct list_head **p, - struct posix_acl *pacl, struct posix_acl_entry **pace, - unsigned int flags) -{ - int error = -EINVAL; - struct nfs4_ace *ace, *ace2; +/* + * While processing the NFSv4 ACE, this maintains bitmasks representing + * which permission bits have been allowed and which denied to a given + * entity: */ +struct posix_ace_state { + u32 allow; + u32 deny; +}; - ace = get_next_v4_ace(p, &n4acl->ace_head); - if (ace == NULL) - goto out; - if (ace2type(ace) != ACL_USER_OBJ) - goto out; - error = write_pace(ace, pacl, pace, ACL_USER_OBJ, flags); - if (error < 0) - goto out; - error = -EINVAL; - ace2 = get_next_v4_ace(p, &n4acl->ace_head); - if (ace2 == NULL) - goto out; - if (!complementary_ace_pair(ace, ace2, flags)) - goto out; - error = 0; -out: - return error; -} +struct posix_user_ace_state { + uid_t uid; + struct posix_ace_state perms; +}; -static inline int -users_from_v4(struct nfs4_acl *n4acl, struct list_head **p, - struct nfs4_ace **mask_ace, - struct posix_acl *pacl, struct posix_acl_entry **pace, - unsigned int flags) -{ - int error = -EINVAL; - struct nfs4_ace *ace, *ace2; +struct posix_ace_state_array { + int n; + struct posix_user_ace_state aces[]; +}; - ace = get_next_v4_ace(p, &n4acl->ace_head); - if (ace == NULL) - goto out; - while (ace2type(ace) == ACL_USER) { - if (ace->type != NFS4_ACE_ACCESS_DENIED_ACE_TYPE) - goto out; - if (*mask_ace && - !MASK_EQUAL(ace->access_mask, (*mask_ace)->access_mask)) - goto out; - *mask_ace = ace; - ace = get_next_v4_ace(p, &n4acl->ace_head); - if (ace == NULL) - goto out; - if (ace->type != NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) - goto out; - error = write_pace(ace, pacl, pace, ACL_USER, flags); - if (error < 0) - goto out; - error = -EINVAL; - ace2 = get_next_v4_ace(p, &n4acl->ace_head); - if (ace2 == NULL) - goto out; - if (!complementary_ace_pair(ace, ace2, flags)) - goto out; - if ((*mask_ace)->flag != ace2->flag || - !same_who(*mask_ace, ace2)) - goto out; - ace = get_next_v4_ace(p, &n4acl->ace_head); - if (ace == NULL) - goto out; - } - error = 0; -out: - return error; -} +/* + * While processing the NFSv4 ACE, this maintains the partial permissions + * calculated so far: */ + +struct posix_acl_state { + struct posix_ace_state owner; + struct posix_ace_state group; + struct posix_ace_state other; + struct posix_ace_state everyone; + struct posix_ace_state mask; /* Deny unused in this case */ + struct posix_ace_state_array *users; + struct posix_ace_state_array *groups; +}; -static inline int -group_obj_and_groups_from_v4(struct nfs4_acl *n4acl, struct list_head **p, - struct nfs4_ace **mask_ace, - struct posix_acl *pacl, struct posix_acl_entry **pace, - unsigned int flags) +static int +init_state(struct posix_acl_state *state, int cnt) { - int error = -EINVAL; - struct nfs4_ace *ace, *ace2; - struct ace_container *ac; - struct list_head group_l; - - INIT_LIST_HEAD(&group_l); - ace = list_entry(*p, struct nfs4_ace, l_ace); - - /* group owner (mask and allow aces) */ - - if (pacl->a_count != 3) { - /* then the group owner should be preceded by mask */ - if (ace->type != NFS4_ACE_ACCESS_DENIED_ACE_TYPE) - goto out; - if (*mask_ace && - !MASK_EQUAL(ace->access_mask, (*mask_ace)->access_mask)) - goto out; - *mask_ace = ace; - ace = get_next_v4_ace(p, &n4acl->ace_head); - if (ace == NULL) - goto out; + int alloc; - if ((*mask_ace)->flag != ace->flag || !same_who(*mask_ace, ace)) - goto out; + memset(state, 0, sizeof(struct posix_acl_state)); + /* + * In the worst case, each individual acl could be for a distinct + * named user or group, but we don't no which, so we allocate + * enough space for either: + */ + alloc = sizeof(struct posix_ace_state_array) + + cnt*sizeof(struct posix_ace_state); + state->users = kzalloc(alloc, GFP_KERNEL); + if (!state->users) + return -ENOMEM; + state->groups = kzalloc(alloc, GFP_KERNEL); + if (!state->groups) { + kfree(state->users); + return -ENOMEM; } + return 0; +} - if (ace2type(ace) != ACL_GROUP_OBJ) - goto out; - - ac = kmalloc(sizeof(*ac), GFP_KERNEL); - error = -ENOMEM; - if (ac == NULL) - goto out; - ac->ace = ace; - list_add_tail(&ac->ace_l, &group_l); - - error = -EINVAL; - if (ace->type != NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) - goto out; - - error = write_pace(ace, pacl, pace, ACL_GROUP_OBJ, flags); - if (error < 0) - goto out; - - error = -EINVAL; - ace = get_next_v4_ace(p, &n4acl->ace_head); - if (ace == NULL) - goto out; +static void +free_state(struct posix_acl_state *state) { + kfree(state->users); + kfree(state->groups); +} + +static inline void add_to_mask(struct posix_acl_state *state, struct posix_ace_state *astate) +{ + state->mask.allow |= astate->allow; +} + +/* + * Certain bits (SYNCHRONIZE, DELETE, WRITE_OWNER, READ/WRITE_NAMED_ATTRS, + * READ_ATTRIBUTES, READ_ACL) are currently unenforceable and don't translate + * to traditional read/write/execute permissions. + * + * It's problematic to reject acls that use certain mode bits, because it + * places the burden on users to learn the rules about which bits one + * particular server sets, without giving the user a lot of help--we return an + * error that could mean any number of different things. To make matters + * worse, the problematic bits might be introduced by some application that's + * automatically mapping from some other acl model. + * + * So wherever possible we accept anything, possibly erring on the side of + * denying more permissions than necessary. + * + * However we do reject *explicit* DENY's of a few bits representing + * permissions we could never deny: + */ - /* groups (mask and allow aces) */ +static inline int check_deny(u32 mask, int isowner) +{ + if (mask & (NFS4_ACE_READ_ATTRIBUTES | NFS4_ACE_READ_ACL)) + return -EINVAL; + if (!isowner) + return 0; + if (mask & (NFS4_ACE_WRITE_ATTRIBUTES | NFS4_ACE_WRITE_ACL)) + return -EINVAL; + return 0; +} - while (ace2type(ace) == ACL_GROUP) { - if (*mask_ace == NULL) - goto out; +static struct posix_acl * +posix_state_to_acl(struct posix_acl_state *state, unsigned int flags) +{ + struct posix_acl_entry *pace; + struct posix_acl *pacl; + int nace; + int i, error = 0; - if (ace->type != NFS4_ACE_ACCESS_DENIED_ACE_TYPE || - !MASK_EQUAL(ace->access_mask, (*mask_ace)->access_mask)) - goto out; - *mask_ace = ace; + nace = 4 + state->users->n + state->groups->n; + pacl = posix_acl_alloc(nace, GFP_KERNEL); + if (!pacl) + return ERR_PTR(-ENOMEM); - ace = get_next_v4_ace(p, &n4acl->ace_head); - if (ace == NULL) - goto out; - ac = kmalloc(sizeof(*ac), GFP_KERNEL); - error = -ENOMEM; - if (ac == NULL) - goto out; - error = -EINVAL; - if (ace->type != NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE || - !same_who(ace, *mask_ace)) - goto out; + pace = pacl->a_entries; + pace->e_tag = ACL_USER_OBJ; + error = check_deny(state->owner.deny, 1); + if (error) + goto out_err; + low_mode_from_nfs4(state->owner.allow, &pace->e_perm, flags); + pace->e_id = ACL_UNDEFINED_ID; - ac->ace = ace; - list_add_tail(&ac->ace_l, &group_l); + for (i=0; i < state->users->n; i++) { + pace++; + pace->e_tag = ACL_USER; + error = check_deny(state->users->aces[i].perms.deny, 0); + if (error) + goto out_err; + low_mode_from_nfs4(state->users->aces[i].perms.allow, + &pace->e_perm, flags); + pace->e_id = state->users->aces[i].uid; + add_to_mask(state, &state->users->aces[i].perms); + } + + pace++; + pace->e_tag = ACL_GROUP_OBJ; + error = check_deny(state->group.deny, 0); + if (error) + goto out_err; + low_mode_from_nfs4(state->group.allow, &pace->e_perm, flags); + pace->e_id = ACL_UNDEFINED_ID; + add_to_mask(state, &state->group); + + for (i=0; i < state->groups->n; i++) { + pace++; + pace->e_tag = ACL_GROUP; + error = check_deny(state->groups->aces[i].perms.deny, 0); + if (error) + goto out_err; + low_mode_from_nfs4(state->groups->aces[i].perms.allow, + &pace->e_perm, flags); + pace->e_id = state->groups->aces[i].uid; + add_to_mask(state, &state->groups->aces[i].perms); + } + + pace++; + pace->e_tag = ACL_MASK; + low_mode_from_nfs4(state->mask.allow, &pace->e_perm, flags); + pace->e_id = ACL_UNDEFINED_ID; + + pace++; + pace->e_tag = ACL_OTHER; + error = check_deny(state->other.deny, 0); + if (error) + goto out_err; + low_mode_from_nfs4(state->other.allow, &pace->e_perm, flags); + pace->e_id = ACL_UNDEFINED_ID; - error = write_pace(ace, pacl, pace, ACL_GROUP, flags); - if (error < 0) - goto out; - error = -EINVAL; - ace = get_next_v4_ace(p, &n4acl->ace_head); - if (ace == NULL) - goto out; - } + return pacl; +out_err: + posix_acl_release(pacl); + return ERR_PTR(error); +} - /* group owner (deny ace) */ +static inline void allow_bits(struct posix_ace_state *astate, u32 mask) +{ + /* Allow all bits in the mask not already denied: */ + astate->allow |= mask & ~astate->deny; +} - if (ace2type(ace) != ACL_GROUP_OBJ) - goto out; - ac = list_entry(group_l.next, struct ace_container, ace_l); - ace2 = ac->ace; - if (!complementary_ace_pair(ace2, ace, flags)) - goto out; - list_del(group_l.next); - kfree(ac); +static inline void deny_bits(struct posix_ace_state *astate, u32 mask) +{ + /* Deny all bits in the mask not already allowed: */ + astate->deny |= mask & ~astate->allow; +} - /* groups (deny aces) */ +static int find_uid(struct posix_acl_state *state, struct posix_ace_state_array *a, uid_t uid) +{ + int i; - while (!list_empty(&group_l)) { - ace = get_next_v4_ace(p, &n4acl->ace_head); - if (ace == NULL) - goto out; - if (ace2type(ace) != ACL_GROUP) - goto out; - ac = list_entry(group_l.next, struct ace_container, ace_l); - ace2 = ac->ace; - if (!complementary_ace_pair(ace2, ace, flags)) - goto out; - list_del(group_l.next); - kfree(ac); - } + for (i = 0; i < a->n; i++) + if (a->aces[i].uid == uid) + return i; + /* Not found: */ + a->n++; + a->aces[i].uid = uid; + a->aces[i].perms.allow = state->everyone.allow; + a->aces[i].perms.deny = state->everyone.deny; - ace = get_next_v4_ace(p, &n4acl->ace_head); - if (ace == NULL) - goto out; - if (ace2type(ace) != ACL_OTHER) - goto out; - error = 0; -out: - while (!list_empty(&group_l)) { - ac = list_entry(group_l.next, struct ace_container, ace_l); - list_del(group_l.next); - kfree(ac); - } - return error; + return i; } -static inline int -mask_from_v4(struct nfs4_acl *n4acl, struct list_head **p, - struct nfs4_ace **mask_ace, - struct posix_acl *pacl, struct posix_acl_entry **pace, - unsigned int flags) +static void deny_bits_array(struct posix_ace_state_array *a, u32 mask) { - int error = -EINVAL; - struct nfs4_ace *ace; + int i; - ace = list_entry(*p, struct nfs4_ace, l_ace); - if (pacl->a_count != 3) { - if (*mask_ace == NULL) - goto out; - (*mask_ace)->access_mask = deny_mask((*mask_ace)->access_mask, flags); - write_pace(*mask_ace, pacl, pace, ACL_MASK, flags); - } - error = 0; -out: - return error; + for (i=0; i < a->n; i++) + deny_bits(&a->aces[i].perms, mask); } -static inline int -other_from_v4(struct nfs4_acl *n4acl, struct list_head **p, - struct posix_acl *pacl, struct posix_acl_entry **pace, - unsigned int flags) +static void allow_bits_array(struct posix_ace_state_array *a, u32 mask) { - int error = -EINVAL; - struct nfs4_ace *ace, *ace2; + int i; - ace = list_entry(*p, struct nfs4_ace, l_ace); - if (ace->type != NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) - goto out; - error = write_pace(ace, pacl, pace, ACL_OTHER, flags); - if (error < 0) - goto out; - error = -EINVAL; - ace2 = get_next_v4_ace(p, &n4acl->ace_head); - if (ace2 == NULL) - goto out; - if (!complementary_ace_pair(ace, ace2, flags)) - goto out; - error = 0; -out: - return error; + for (i=0; i < a->n; i++) + allow_bits(&a->aces[i].perms, mask); } -static int -calculate_posix_ace_count(struct nfs4_acl *n4acl) +static void process_one_v4_ace(struct posix_acl_state *state, + struct nfs4_ace *ace) { - if (n4acl->naces == 6) /* owner, owner group, and other only */ - return 3; - else { /* Otherwise there must be a mask entry. */ - /* Also, the remaining entries are for named users and - * groups, and come in threes (mask, allow, deny): */ - if (n4acl->naces < 7) - return -EINVAL; - if ((n4acl->naces - 7) % 3) - return -EINVAL; - return 4 + (n4acl->naces - 7)/3; + u32 mask = ace->access_mask; + int i; + + switch (ace2type(ace)) { + case ACL_USER_OBJ: + if (ace->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) { + allow_bits(&state->owner, mask); + } else { + deny_bits(&state->owner, mask); + } + break; + case ACL_USER: + i = find_uid(state, state->users, ace->who); + if (ace->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) { + allow_bits(&state->users->aces[i].perms, mask); + } else { + deny_bits(&state->users->aces[i].perms, mask); + mask = state->users->aces[i].perms.deny; + deny_bits(&state->owner, mask); + } + break; + case ACL_GROUP_OBJ: + if (ace->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) { + allow_bits(&state->group, mask); + } else { + deny_bits(&state->group, mask); + mask = state->group.deny; + deny_bits(&state->owner, mask); + deny_bits(&state->everyone, mask); + deny_bits_array(state->users, mask); + deny_bits_array(state->groups, mask); + } + break; + case ACL_GROUP: + i = find_uid(state, state->groups, ace->who); + if (ace->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) { + allow_bits(&state->groups->aces[i].perms, mask); + } else { + deny_bits(&state->groups->aces[i].perms, mask); + mask = state->groups->aces[i].perms.deny; + deny_bits(&state->owner, mask); + deny_bits(&state->group, mask); + deny_bits(&state->everyone, mask); + deny_bits_array(state->users, mask); + deny_bits_array(state->groups, mask); + } + break; + case ACL_OTHER: + if (ace->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) { + allow_bits(&state->owner, mask); + allow_bits(&state->group, mask); + allow_bits(&state->other, mask); + allow_bits(&state->everyone, mask); + allow_bits_array(state->users, mask); + allow_bits_array(state->groups, mask); + } else { + deny_bits(&state->owner, mask); + deny_bits(&state->group, mask); + deny_bits(&state->other, mask); + deny_bits(&state->everyone, mask); + deny_bits_array(state->users, mask); + deny_bits_array(state->groups, mask); + } } } - static struct posix_acl * _nfsv4_to_posix_one(struct nfs4_acl *n4acl, unsigned int flags) { + struct posix_acl_state state; struct posix_acl *pacl; - int error = -EINVAL, nace = 0; - struct list_head *p; - struct nfs4_ace *mask_ace = NULL; - struct posix_acl_entry *pace; - - nace = calculate_posix_ace_count(n4acl); - if (nace < 0) - goto out_err; - - pacl = posix_acl_alloc(nace, GFP_KERNEL); - error = -ENOMEM; - if (pacl == NULL) - goto out_err; + struct nfs4_ace *ace; + int ret; - pace = &pacl->a_entries[0]; - p = &n4acl->ace_head; + ret = init_state(&state, n4acl->naces); + if (ret) + return ERR_PTR(ret); - error = user_obj_from_v4(n4acl, &p, pacl, &pace, flags); - if (error) - goto out_acl; + list_for_each_entry(ace, &n4acl->ace_head, l_ace) + process_one_v4_ace(&state, ace); - error = users_from_v4(n4acl, &p, &mask_ace, pacl, &pace, flags); - if (error) - goto out_acl; + pacl = posix_state_to_acl(&state, flags); - error = group_obj_and_groups_from_v4(n4acl, &p, &mask_ace, pacl, &pace, - flags); - if (error) - goto out_acl; + free_state(&state); - error = mask_from_v4(n4acl, &p, &mask_ace, pacl, &pace, flags); - if (error) - goto out_acl; - error = other_from_v4(n4acl, &p, pacl, &pace, flags); - if (error) - goto out_acl; - - error = -EINVAL; - if (p->next != &n4acl->ace_head) - goto out_acl; - if (pace != pacl->a_entries + pacl->a_count) - goto out_acl; - - sort_pacl(pacl); - - return pacl; -out_acl: - posix_acl_release(pacl); -out_err: - pacl = ERR_PTR(error); + if (!IS_ERR(pacl)) + sort_pacl(pacl); return pacl; } @@ -785,6 +717,10 @@ nfs4_acl_split(struct nfs4_acl *acl, str list_for_each_safe(h, n, &acl->ace_head) { ace = list_entry(h, struct nfs4_ace, l_ace); + if (ace->type != NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE && + ace->type != NFS4_ACE_ACCESS_DENIED_ACE_TYPE) + return -EINVAL; + if ((ace->flag & NFS4_INHERITANCE_FLAGS) != NFS4_INHERITANCE_FLAGS) continue; @@ -930,23 +866,6 @@ nfs4_acl_write_who(int who, char *p) return -1; } -static inline int -match_who(struct nfs4_ace *ace, uid_t owner, gid_t group, uid_t who) -{ - switch (ace->whotype) { - case NFS4_ACL_WHO_NAMED: - return who == ace->who; - case NFS4_ACL_WHO_OWNER: - return who == owner; - case NFS4_ACL_WHO_GROUP: - return who == group; - case NFS4_ACL_WHO_EVERYONE: - return 1; - default: - return 0; - } -} - EXPORT_SYMBOL(nfs4_acl_new); EXPORT_SYMBOL(nfs4_acl_free); EXPORT_SYMBOL(nfs4_acl_add_ace); ^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH 007 of 9] knfsd: nfsd4: acls: fix inheritance 2006-09-04 23:15 [PATCH 000 of 9] knfsd: minor gss/v4 cleanups and major ACL surgery NeilBrown ` (5 preceding siblings ...) 2006-09-04 23:15 ` [PATCH 006 of 9] knfsd: nfsd4: acls: relax the nfsv4->posix mapping NeilBrown @ 2006-09-04 23:15 ` NeilBrown 2006-09-04 23:16 ` [PATCH 008 of 9] knfsd: nfsd4: acls: simplify nfs4_acl_nfsv4_to_posix interface NeilBrown 2006-09-04 23:16 ` [PATCH 009 of 9] knfsd: nfsd4: acls: fix handling of zero-length acls NeilBrown 8 siblings, 0 replies; 10+ messages in thread From: NeilBrown @ 2006-09-04 23:15 UTC (permalink / raw) To: Andrew Morton; +Cc: nfs, linux-kernel From: J.Bruce Fields <bfields@fieldses.org> We can be a little more flexible about the flags allowed for inheritance (in particular, we can deal with either the presence or the absence of INHERIT_ONLY), but we should probably reject other combinations that we don't understand. Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu> Signed-off-by: Neil Brown <neilb@suse.de> ### Diffstat output ./fs/nfsd/nfs4acl.c | 43 ++++++++++++++++++++++++++++++------------- 1 file changed, 30 insertions(+), 13 deletions(-) diff .prev/fs/nfsd/nfs4acl.c ./fs/nfsd/nfs4acl.c --- .prev/fs/nfsd/nfs4acl.c 2006-09-04 17:20:49.000000000 +1000 +++ ./fs/nfsd/nfs4acl.c 2006-09-04 17:26:00.000000000 +1000 @@ -63,6 +63,8 @@ #define NFS4_INHERITANCE_FLAGS (NFS4_ACE_FILE_INHERIT_ACE \ | NFS4_ACE_DIRECTORY_INHERIT_ACE | NFS4_ACE_INHERIT_ONLY_ACE) +#define NFS4_SUPPORTED_FLAGS (NFS4_INHERITANCE_FLAGS | NFS4_ACE_IDENTIFIER_GROUP) + #define MASK_EQUAL(mask1, mask2) \ ( ((mask1) & NFS4_ACE_MASK_ALL) == ((mask2) & NFS4_ACE_MASK_ALL) ) @@ -721,22 +723,37 @@ nfs4_acl_split(struct nfs4_acl *acl, str ace->type != NFS4_ACE_ACCESS_DENIED_ACE_TYPE) return -EINVAL; - if ((ace->flag & NFS4_INHERITANCE_FLAGS) - != NFS4_INHERITANCE_FLAGS) - continue; + if (ace->flag & ~NFS4_SUPPORTED_FLAGS) + return -EINVAL; - error = nfs4_acl_add_ace(dacl, ace->type, ace->flag, + switch (ace->flag & NFS4_INHERITANCE_FLAGS) { + case 0: + /* Leave this ace in the effective acl: */ + continue; + case NFS4_INHERITANCE_FLAGS: + /* Add this ace to the default acl and remove it + * from the effective acl: */ + error = nfs4_acl_add_ace(dacl, ace->type, ace->flag, ace->access_mask, ace->whotype, ace->who); - if (error < 0) - goto out; - - list_del(h); - kfree(ace); - acl->naces--; + if (error) + return error; + list_del(h); + kfree(ace); + acl->naces--; + break; + case NFS4_INHERITANCE_FLAGS & ~NFS4_ACE_INHERIT_ONLY_ACE: + /* Add this ace to the default, but leave it in + * the effective acl as well: */ + error = nfs4_acl_add_ace(dacl, ace->type, ace->flag, + ace->access_mask, ace->whotype, ace->who); + if (error) + return error; + break; + default: + return -EINVAL; + } } - -out: - return error; + return 0; } static short ^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH 008 of 9] knfsd: nfsd4: acls: simplify nfs4_acl_nfsv4_to_posix interface 2006-09-04 23:15 [PATCH 000 of 9] knfsd: minor gss/v4 cleanups and major ACL surgery NeilBrown ` (6 preceding siblings ...) 2006-09-04 23:15 ` [PATCH 007 of 9] knfsd: nfsd4: acls: fix inheritance NeilBrown @ 2006-09-04 23:16 ` NeilBrown 2006-09-04 23:16 ` [PATCH 009 of 9] knfsd: nfsd4: acls: fix handling of zero-length acls NeilBrown 8 siblings, 0 replies; 10+ messages in thread From: NeilBrown @ 2006-09-04 23:16 UTC (permalink / raw) To: Andrew Morton; +Cc: nfs, linux-kernel From: J.Bruce Fields <bfields@fieldses.org> There's no need to handle the case where the caller passes in null for pacl or dpacl; no caller does that, because it would be a dumb thing to do. Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu> Signed-off-by: Neil Brown <neilb@suse.de> ### Diffstat output ./fs/nfsd/nfs4acl.c | 48 +++++++++++++++++++++--------------------------- 1 file changed, 21 insertions(+), 27 deletions(-) diff .prev/fs/nfsd/nfs4acl.c ./fs/nfsd/nfs4acl.c --- .prev/fs/nfsd/nfs4acl.c 2006-09-04 17:26:00.000000000 +1000 +++ ./fs/nfsd/nfs4acl.c 2006-09-04 17:27:48.000000000 +1000 @@ -360,39 +360,33 @@ nfs4_acl_nfsv4_to_posix(struct nfs4_acl if (error < 0) goto out_acl; - if (pacl != NULL) { - if (acl->naces == 0) { - error = -ENODATA; - goto try_dpacl; - } - - *pacl = _nfsv4_to_posix_one(acl, flags); - if (IS_ERR(*pacl)) { - error = PTR_ERR(*pacl); - *pacl = NULL; - goto out_acl; - } + if (acl->naces == 0) { + error = -ENODATA; + goto try_dpacl; } + *pacl = _nfsv4_to_posix_one(acl, flags); + if (IS_ERR(*pacl)) { + error = PTR_ERR(*pacl); + *pacl = NULL; + goto out_acl; + } try_dpacl: - if (dpacl != NULL) { - if (dacl->naces == 0) { - if (pacl == NULL || *pacl == NULL) - error = -ENODATA; - goto out_acl; - } - - error = 0; - *dpacl = _nfsv4_to_posix_one(dacl, flags); - if (IS_ERR(*dpacl)) { - error = PTR_ERR(*dpacl); - *dpacl = NULL; - goto out_acl; - } + if (dacl->naces == 0) { + if (pacl == NULL || *pacl == NULL) + error = -ENODATA; + goto out_acl; } + error = 0; + *dpacl = _nfsv4_to_posix_one(dacl, flags); + if (IS_ERR(*dpacl)) { + error = PTR_ERR(*dpacl); + *dpacl = NULL; + goto out_acl; + } out_acl: - if (error && pacl) { + if (error) { posix_acl_release(*pacl); *pacl = NULL; } ^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH 009 of 9] knfsd: nfsd4: acls: fix handling of zero-length acls 2006-09-04 23:15 [PATCH 000 of 9] knfsd: minor gss/v4 cleanups and major ACL surgery NeilBrown ` (7 preceding siblings ...) 2006-09-04 23:16 ` [PATCH 008 of 9] knfsd: nfsd4: acls: simplify nfs4_acl_nfsv4_to_posix interface NeilBrown @ 2006-09-04 23:16 ` NeilBrown 8 siblings, 0 replies; 10+ messages in thread From: NeilBrown @ 2006-09-04 23:16 UTC (permalink / raw) To: Andrew Morton; +Cc: nfs, linux-kernel From: J.Bruce Fields <bfields@fieldses.org> It is legal to have zero-length NFSv4 acls; they just deny everything. Also, nfs4_acl_nfsv4_to_posix will always return with pacl and dpacl set on success, so the caller doesn't need to check this. Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu> Signed-off-by: Neil Brown <neilb@suse.de> ### Diffstat output ./fs/nfsd/nfs4acl.c | 15 +-------------- ./fs/nfsd/vfs.c | 10 ++++------ 2 files changed, 5 insertions(+), 20 deletions(-) diff .prev/fs/nfsd/nfs4acl.c ./fs/nfsd/nfs4acl.c --- .prev/fs/nfsd/nfs4acl.c 2006-09-04 17:27:48.000000000 +1000 +++ ./fs/nfsd/nfs4acl.c 2006-09-04 17:28:10.000000000 +1000 @@ -357,33 +357,20 @@ nfs4_acl_nfsv4_to_posix(struct nfs4_acl goto out; error = nfs4_acl_split(acl, dacl); - if (error < 0) + if (error) goto out_acl; - if (acl->naces == 0) { - error = -ENODATA; - goto try_dpacl; - } - *pacl = _nfsv4_to_posix_one(acl, flags); if (IS_ERR(*pacl)) { error = PTR_ERR(*pacl); *pacl = NULL; goto out_acl; } -try_dpacl: - if (dacl->naces == 0) { - if (pacl == NULL || *pacl == NULL) - error = -ENODATA; - goto out_acl; - } - error = 0; *dpacl = _nfsv4_to_posix_one(dacl, flags); if (IS_ERR(*dpacl)) { error = PTR_ERR(*dpacl); *dpacl = NULL; - goto out_acl; } out_acl: if (error) { diff .prev/fs/nfsd/vfs.c ./fs/nfsd/vfs.c --- .prev/fs/nfsd/vfs.c 2006-09-04 17:09:47.000000000 +1000 +++ ./fs/nfsd/vfs.c 2006-09-04 17:28:10.000000000 +1000 @@ -447,13 +447,11 @@ nfsd4_set_nfs4_acl(struct svc_rqst *rqst } else if (error < 0) goto out_nfserr; - if (pacl) { - error = set_nfsv4_acl_one(dentry, pacl, POSIX_ACL_XATTR_ACCESS); - if (error < 0) - goto out_nfserr; - } + error = set_nfsv4_acl_one(dentry, pacl, POSIX_ACL_XATTR_ACCESS); + if (error < 0) + goto out_nfserr; - if (dpacl) { + if (S_ISDIR(inode->i_mode)) { error = set_nfsv4_acl_one(dentry, dpacl, POSIX_ACL_XATTR_DEFAULT); if (error < 0) goto out_nfserr; ^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2006-09-04 23:18 UTC | newest] Thread overview: 10+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2006-09-04 23:15 [PATCH 000 of 9] knfsd: minor gss/v4 cleanups and major ACL surgery NeilBrown 2006-09-04 23:15 ` [PATCH 001 of 9] knfsd: svcrpc: gss: factor out some common wrapping code NeilBrown 2006-09-04 23:15 ` [PATCH 002 of 9] knfsd: svcrpc: gss: fix failure on SVC_DENIED in integrity case NeilBrown 2006-09-04 23:15 ` [PATCH 003 of 9] knfsd: svcrpc: use consistent variable name for the reply state NeilBrown 2006-09-04 23:15 ` [PATCH 004 of 9] knfsd: nfsd4: refactor exp_pseudoroot NeilBrown 2006-09-04 23:15 ` [PATCH 005 of 9] knfsd: nfsd4: clean up exp_pseudoroot NeilBrown 2006-09-04 23:15 ` [PATCH 006 of 9] knfsd: nfsd4: acls: relax the nfsv4->posix mapping NeilBrown 2006-09-04 23:15 ` [PATCH 007 of 9] knfsd: nfsd4: acls: fix inheritance NeilBrown 2006-09-04 23:16 ` [PATCH 008 of 9] knfsd: nfsd4: acls: simplify nfs4_acl_nfsv4_to_posix interface NeilBrown 2006-09-04 23:16 ` [PATCH 009 of 9] knfsd: nfsd4: acls: fix handling of zero-length acls NeilBrown
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox