Skip to content

Commit 5fc51df

Browse files
rmacklemchucklever
authored andcommitted
NFSD: Add support for XDR decoding POSIX draft ACLs
The POSIX ACL extension to NFSv4 defines FATTR4_POSIX_ACCESS_ACL and FATTR4_POSIX_DEFAULT_ACL for setting access and default ACLs via CREATE, OPEN, and SETATTR operations. This patch adds the XDR decoders for those attributes. The nfsd4_decode_fattr4() function gains two additional parameters for receiving decoded POSIX ACLs. CREATE, OPEN, and SETATTR decoders pass pointers to these new parameters, enabling clients to set POSIX ACLs during object creation or modification. Signed-off-by: Rick Macklem <rmacklem@uoguelph.ca> Reviewed-by: Jeff Layton <jlayton@kernel.org> Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
1 parent 345c4b7 commit 5fc51df

4 files changed

Lines changed: 162 additions & 10 deletions

File tree

fs/nfsd/acl.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,5 +49,6 @@ int nfsd4_get_nfs4_acl(struct svc_rqst *rqstp, struct dentry *dentry,
4949
struct nfs4_acl **acl);
5050
__be32 nfsd4_acl_to_attr(enum nfs_ftype4 type, struct nfs4_acl *acl,
5151
struct nfsd_attrs *attr);
52+
void sort_pacl_range(struct posix_acl *pacl, int start, int end);
5253

5354
#endif /* LINUX_NFS4_ACL_H */

fs/nfsd/nfs4acl.c

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -369,12 +369,21 @@ pace_gt(struct posix_acl_entry *pace1, struct posix_acl_entry *pace2)
369369
return false;
370370
}
371371

372-
static void
373-
sort_pacl_range(struct posix_acl *pacl, int start, int end) {
372+
/**
373+
* sort_pacl_range - sort a range of POSIX ACL entries by tag and id
374+
* @pacl: POSIX ACL containing entries to sort
375+
* @start: starting index of range to sort
376+
* @end: ending index of range to sort (inclusive)
377+
*
378+
* Sorts ACL entries in place so that USER entries are ordered by UID
379+
* and GROUP entries are ordered by GID. Required before calling
380+
* posix_acl_valid().
381+
*/
382+
void sort_pacl_range(struct posix_acl *pacl, int start, int end)
383+
{
374384
int sorted = 0, i;
375385

376-
/* We just do a bubble sort; easy to do in place, and we're not
377-
* expecting acl's to be long enough to justify anything more. */
386+
/* Bubble sort: acceptable here because ACLs are typically short. */
378387
while (!sorted) {
379388
sorted = 1;
380389
for (i = start; i < end; i++) {

fs/nfsd/nfs4xdr.c

Lines changed: 142 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -378,10 +378,111 @@ nfsd4_decode_security_label(struct nfsd4_compoundargs *argp,
378378
return nfs_ok;
379379
}
380380

381+
#ifdef CONFIG_NFSD_V4_POSIX_ACLS
382+
383+
static short nfsd4_posixacetag4_to_tag(posixacetag4 tag)
384+
{
385+
switch (tag) {
386+
case POSIXACE4_TAG_USER_OBJ: return ACL_USER_OBJ;
387+
case POSIXACE4_TAG_GROUP_OBJ: return ACL_GROUP_OBJ;
388+
case POSIXACE4_TAG_USER: return ACL_USER;
389+
case POSIXACE4_TAG_GROUP: return ACL_GROUP;
390+
case POSIXACE4_TAG_MASK: return ACL_MASK;
391+
case POSIXACE4_TAG_OTHER: return ACL_OTHER;
392+
}
393+
return ACL_OTHER;
394+
}
395+
396+
static __be32
397+
nfsd4_decode_posixace4(struct nfsd4_compoundargs *argp,
398+
struct posix_acl_entry *ace)
399+
{
400+
posixaceperm4 perm;
401+
__be32 *p, status;
402+
posixacetag4 tag;
403+
u32 len;
404+
405+
if (!xdrgen_decode_posixacetag4(argp->xdr, &tag))
406+
return nfserr_bad_xdr;
407+
ace->e_tag = nfsd4_posixacetag4_to_tag(tag);
408+
409+
if (!xdrgen_decode_posixaceperm4(argp->xdr, &perm))
410+
return nfserr_bad_xdr;
411+
if (perm & ~S_IRWXO)
412+
return nfserr_bad_xdr;
413+
ace->e_perm = perm;
414+
415+
if (xdr_stream_decode_u32(argp->xdr, &len) < 0)
416+
return nfserr_bad_xdr;
417+
p = xdr_inline_decode(argp->xdr, len);
418+
if (!p)
419+
return nfserr_bad_xdr;
420+
switch (tag) {
421+
case POSIXACE4_TAG_USER:
422+
if (len > 0)
423+
status = nfsd_map_name_to_uid(argp->rqstp,
424+
(char *)p, len, &ace->e_uid);
425+
else
426+
status = nfserr_bad_xdr;
427+
break;
428+
case POSIXACE4_TAG_GROUP:
429+
if (len > 0)
430+
status = nfsd_map_name_to_gid(argp->rqstp,
431+
(char *)p, len, &ace->e_gid);
432+
else
433+
status = nfserr_bad_xdr;
434+
break;
435+
default:
436+
status = nfs_ok;
437+
}
438+
439+
return status;
440+
}
441+
442+
static noinline __be32
443+
nfsd4_decode_posixacl(struct nfsd4_compoundargs *argp, struct posix_acl **acl)
444+
{
445+
struct posix_acl_entry *ace;
446+
__be32 status;
447+
u32 count;
448+
449+
if (xdr_stream_decode_u32(argp->xdr, &count) < 0)
450+
return nfserr_bad_xdr;
451+
452+
*acl = posix_acl_alloc(count, GFP_KERNEL);
453+
if (*acl == NULL)
454+
return nfserr_resource;
455+
456+
(*acl)->a_count = count;
457+
for (ace = (*acl)->a_entries; ace < (*acl)->a_entries + count; ace++) {
458+
status = nfsd4_decode_posixace4(argp, ace);
459+
if (status) {
460+
posix_acl_release(*acl);
461+
*acl = NULL;
462+
return status;
463+
}
464+
}
465+
466+
/*
467+
* posix_acl_valid() requires the ACEs to be sorted.
468+
* If they are already sorted, sort_pacl_range() will return
469+
* after one pass through the ACEs, since it implements bubble sort.
470+
* Note that a count == 0 is used to delete a POSIX ACL and a count
471+
* of 1 or 2 will always be found invalid by posix_acl_valid().
472+
*/
473+
if (count >= 3)
474+
sort_pacl_range(*acl, 0, count - 1);
475+
476+
return nfs_ok;
477+
}
478+
479+
#endif /* CONFIG_NFSD_V4_POSIX_ACLS */
480+
381481
static __be32
382482
nfsd4_decode_fattr4(struct nfsd4_compoundargs *argp, u32 *bmval, u32 bmlen,
383483
struct iattr *iattr, struct nfs4_acl **acl,
384-
struct xdr_netobj *label, int *umask)
484+
struct xdr_netobj *label, int *umask,
485+
struct posix_acl **dpaclp, struct posix_acl **paclp)
385486
{
386487
unsigned int starting_pos;
387488
u32 attrlist4_count;
@@ -544,9 +645,40 @@ nfsd4_decode_fattr4(struct nfsd4_compoundargs *argp, u32 *bmval, u32 bmlen,
544645
ATTR_MTIME | ATTR_MTIME_SET | ATTR_DELEG;
545646
}
546647

648+
*dpaclp = NULL;
649+
*paclp = NULL;
650+
#ifdef CONFIG_NFSD_V4_POSIX_ACLS
651+
if (bmval[2] & FATTR4_WORD2_POSIX_DEFAULT_ACL) {
652+
struct posix_acl *dpacl;
653+
654+
status = nfsd4_decode_posixacl(argp, &dpacl);
655+
if (status)
656+
return status;
657+
*dpaclp = dpacl;
658+
}
659+
if (bmval[2] & FATTR4_WORD2_POSIX_ACCESS_ACL) {
660+
struct posix_acl *pacl;
661+
662+
status = nfsd4_decode_posixacl(argp, &pacl);
663+
if (status) {
664+
posix_acl_release(*dpaclp);
665+
*dpaclp = NULL;
666+
return status;
667+
}
668+
*paclp = pacl;
669+
}
670+
#endif /* CONFIG_NFSD_V4_POSIX_ACLS */
671+
547672
/* request sanity: did attrlist4 contain the expected number of words? */
548-
if (attrlist4_count != xdr_stream_pos(argp->xdr) - starting_pos)
673+
if (attrlist4_count != xdr_stream_pos(argp->xdr) - starting_pos) {
674+
#ifdef CONFIG_NFSD_V4_POSIX_ACLS
675+
posix_acl_release(*dpaclp);
676+
posix_acl_release(*paclp);
677+
*dpaclp = NULL;
678+
*paclp = NULL;
679+
#endif
549680
return nfserr_bad_xdr;
681+
}
550682

551683
return nfs_ok;
552684
}
@@ -850,7 +982,8 @@ nfsd4_decode_create(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u)
850982
status = nfsd4_decode_fattr4(argp, create->cr_bmval,
851983
ARRAY_SIZE(create->cr_bmval),
852984
&create->cr_iattr, &create->cr_acl,
853-
&create->cr_label, &create->cr_umask);
985+
&create->cr_label, &create->cr_umask,
986+
&create->cr_dpacl, &create->cr_pacl);
854987
if (status)
855988
return status;
856989

@@ -1001,7 +1134,8 @@ nfsd4_decode_createhow4(struct nfsd4_compoundargs *argp, struct nfsd4_open *open
10011134
status = nfsd4_decode_fattr4(argp, open->op_bmval,
10021135
ARRAY_SIZE(open->op_bmval),
10031136
&open->op_iattr, &open->op_acl,
1004-
&open->op_label, &open->op_umask);
1137+
&open->op_label, &open->op_umask,
1138+
&open->op_dpacl, &open->op_pacl);
10051139
if (status)
10061140
return status;
10071141
break;
@@ -1019,7 +1153,8 @@ nfsd4_decode_createhow4(struct nfsd4_compoundargs *argp, struct nfsd4_open *open
10191153
status = nfsd4_decode_fattr4(argp, open->op_bmval,
10201154
ARRAY_SIZE(open->op_bmval),
10211155
&open->op_iattr, &open->op_acl,
1022-
&open->op_label, &open->op_umask);
1156+
&open->op_label, &open->op_umask,
1157+
&open->op_dpacl, &open->op_pacl);
10231158
if (status)
10241159
return status;
10251160
break;
@@ -1346,7 +1481,8 @@ nfsd4_decode_setattr(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u)
13461481
return nfsd4_decode_fattr4(argp, setattr->sa_bmval,
13471482
ARRAY_SIZE(setattr->sa_bmval),
13481483
&setattr->sa_iattr, &setattr->sa_acl,
1349-
&setattr->sa_label, NULL);
1484+
&setattr->sa_label, NULL, &setattr->sa_dpacl,
1485+
&setattr->sa_pacl);
13501486
}
13511487

13521488
static __be32

fs/nfsd/xdr4.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,8 @@ struct nfsd4_create {
245245
int cr_umask; /* request */
246246
struct nfsd4_change_info cr_cinfo; /* response */
247247
struct nfs4_acl *cr_acl;
248+
struct posix_acl *cr_dpacl;
249+
struct posix_acl *cr_pacl;
248250
struct xdr_netobj cr_label;
249251
};
250252
#define cr_datalen u.link.datalen
@@ -397,6 +399,8 @@ struct nfsd4_open {
397399
struct nfs4_ol_stateid *op_stp; /* used during processing */
398400
struct nfs4_clnt_odstate *op_odstate; /* used during processing */
399401
struct nfs4_acl *op_acl;
402+
struct posix_acl *op_dpacl;
403+
struct posix_acl *op_pacl;
400404
struct xdr_netobj op_label;
401405
struct svc_rqst *op_rqstp;
402406
};
@@ -483,6 +487,8 @@ struct nfsd4_setattr {
483487
struct iattr sa_iattr; /* request */
484488
struct nfs4_acl *sa_acl;
485489
struct xdr_netobj sa_label;
490+
struct posix_acl *sa_dpacl;
491+
struct posix_acl *sa_pacl;
486492
};
487493

488494
struct nfsd4_setclientid {

0 commit comments

Comments
 (0)