Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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>

authored by

Rick Macklem and committed by
Chuck Lever
5fc51dfc 345c4b77

+162 -10
+1
fs/nfsd/acl.h
··· 49 49 struct nfs4_acl **acl); 50 50 __be32 nfsd4_acl_to_attr(enum nfs_ftype4 type, struct nfs4_acl *acl, 51 51 struct nfsd_attrs *attr); 52 + void sort_pacl_range(struct posix_acl *pacl, int start, int end); 52 53 53 54 #endif /* LINUX_NFS4_ACL_H */
+13 -4
fs/nfsd/nfs4acl.c
··· 369 369 return false; 370 370 } 371 371 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 + { 374 384 int sorted = 0, i; 375 385 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. */ 378 387 while (!sorted) { 379 388 sorted = 1; 380 389 for (i = start; i < end; i++) {
+142 -6
fs/nfsd/nfs4xdr.c
··· 378 378 return nfs_ok; 379 379 } 380 380 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 + 381 481 static __be32 382 482 nfsd4_decode_fattr4(struct nfsd4_compoundargs *argp, u32 *bmval, u32 bmlen, 383 483 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) 385 486 { 386 487 unsigned int starting_pos; 387 488 u32 attrlist4_count; ··· 645 544 ATTR_MTIME | ATTR_MTIME_SET | ATTR_DELEG; 646 545 } 647 546 547 + *dpaclp = NULL; 548 + *paclp = NULL; 549 + #ifdef CONFIG_NFSD_V4_POSIX_ACLS 550 + if (bmval[2] & FATTR4_WORD2_POSIX_DEFAULT_ACL) { 551 + struct posix_acl *dpacl; 552 + 553 + status = nfsd4_decode_posixacl(argp, &dpacl); 554 + if (status) 555 + return status; 556 + *dpaclp = dpacl; 557 + } 558 + if (bmval[2] & FATTR4_WORD2_POSIX_ACCESS_ACL) { 559 + struct posix_acl *pacl; 560 + 561 + status = nfsd4_decode_posixacl(argp, &pacl); 562 + if (status) { 563 + posix_acl_release(*dpaclp); 564 + *dpaclp = NULL; 565 + return status; 566 + } 567 + *paclp = pacl; 568 + } 569 + #endif /* CONFIG_NFSD_V4_POSIX_ACLS */ 570 + 648 571 /* request sanity: did attrlist4 contain the expected number of words? */ 649 - if (attrlist4_count != xdr_stream_pos(argp->xdr) - starting_pos) 572 + if (attrlist4_count != xdr_stream_pos(argp->xdr) - starting_pos) { 573 + #ifdef CONFIG_NFSD_V4_POSIX_ACLS 574 + posix_acl_release(*dpaclp); 575 + posix_acl_release(*paclp); 576 + *dpaclp = NULL; 577 + *paclp = NULL; 578 + #endif 650 579 return nfserr_bad_xdr; 580 + } 651 581 652 582 return nfs_ok; 653 583 } ··· 982 850 status = nfsd4_decode_fattr4(argp, create->cr_bmval, 983 851 ARRAY_SIZE(create->cr_bmval), 984 852 &create->cr_iattr, &create->cr_acl, 985 - &create->cr_label, &create->cr_umask); 853 + &create->cr_label, &create->cr_umask, 854 + &create->cr_dpacl, &create->cr_pacl); 986 855 if (status) 987 856 return status; 988 857 ··· 1134 1001 status = nfsd4_decode_fattr4(argp, open->op_bmval, 1135 1002 ARRAY_SIZE(open->op_bmval), 1136 1003 &open->op_iattr, &open->op_acl, 1137 - &open->op_label, &open->op_umask); 1004 + &open->op_label, &open->op_umask, 1005 + &open->op_dpacl, &open->op_pacl); 1138 1006 if (status) 1139 1007 return status; 1140 1008 break; ··· 1153 1019 status = nfsd4_decode_fattr4(argp, open->op_bmval, 1154 1020 ARRAY_SIZE(open->op_bmval), 1155 1021 &open->op_iattr, &open->op_acl, 1156 - &open->op_label, &open->op_umask); 1022 + &open->op_label, &open->op_umask, 1023 + &open->op_dpacl, &open->op_pacl); 1157 1024 if (status) 1158 1025 return status; 1159 1026 break; ··· 1481 1346 return nfsd4_decode_fattr4(argp, setattr->sa_bmval, 1482 1347 ARRAY_SIZE(setattr->sa_bmval), 1483 1348 &setattr->sa_iattr, &setattr->sa_acl, 1484 - &setattr->sa_label, NULL); 1349 + &setattr->sa_label, NULL, &setattr->sa_dpacl, 1350 + &setattr->sa_pacl); 1485 1351 } 1486 1352 1487 1353 static __be32
+6
fs/nfsd/xdr4.h
··· 245 245 int cr_umask; /* request */ 246 246 struct nfsd4_change_info cr_cinfo; /* response */ 247 247 struct nfs4_acl *cr_acl; 248 + struct posix_acl *cr_dpacl; 249 + struct posix_acl *cr_pacl; 248 250 struct xdr_netobj cr_label; 249 251 }; 250 252 #define cr_datalen u.link.datalen ··· 399 397 struct nfs4_ol_stateid *op_stp; /* used during processing */ 400 398 struct nfs4_clnt_odstate *op_odstate; /* used during processing */ 401 399 struct nfs4_acl *op_acl; 400 + struct posix_acl *op_dpacl; 401 + struct posix_acl *op_pacl; 402 402 struct xdr_netobj op_label; 403 403 struct svc_rqst *op_rqstp; 404 404 }; ··· 487 483 struct iattr sa_iattr; /* request */ 488 484 struct nfs4_acl *sa_acl; 489 485 struct xdr_netobj sa_label; 486 + struct posix_acl *sa_dpacl; 487 + struct posix_acl *sa_pacl; 490 488 }; 491 489 492 490 struct nfsd4_setclientid {