.. | .. |
---|
46 | 46 | #include <keys/user-type.h> |
---|
47 | 47 | #include <keys/request_key_auth-type.h> |
---|
48 | 48 | #include <linux/module.h> |
---|
| 49 | +#include <linux/user_namespace.h> |
---|
49 | 50 | |
---|
50 | 51 | #include "internal.h" |
---|
51 | 52 | #include "netns.h" |
---|
.. | .. |
---|
69 | 70 | struct rpc_pipe *idmap_pipe; |
---|
70 | 71 | struct idmap_legacy_upcalldata *idmap_upcall_data; |
---|
71 | 72 | struct mutex idmap_mutex; |
---|
| 73 | + struct user_namespace *user_ns; |
---|
72 | 74 | }; |
---|
| 75 | + |
---|
| 76 | +static struct user_namespace *idmap_userns(const struct idmap *idmap) |
---|
| 77 | +{ |
---|
| 78 | + if (idmap && idmap->user_ns) |
---|
| 79 | + return idmap->user_ns; |
---|
| 80 | + return &init_user_ns; |
---|
| 81 | +} |
---|
73 | 82 | |
---|
74 | 83 | /** |
---|
75 | 84 | * nfs_fattr_init_names - initialise the nfs_fattr owner_name/group_name fields |
---|
.. | .. |
---|
271 | 280 | const char *type, struct idmap *idmap) |
---|
272 | 281 | { |
---|
273 | 282 | char *desc; |
---|
274 | | - struct key *rkey; |
---|
| 283 | + struct key *rkey = ERR_PTR(-EAGAIN); |
---|
275 | 284 | ssize_t ret; |
---|
276 | 285 | |
---|
277 | 286 | ret = nfs_idmap_get_desc(name, namelen, type, strlen(type), &desc); |
---|
278 | 287 | if (ret < 0) |
---|
279 | 288 | return ERR_PTR(ret); |
---|
280 | 289 | |
---|
281 | | - rkey = request_key(&key_type_id_resolver, desc, ""); |
---|
| 290 | + if (!idmap->user_ns || idmap->user_ns == &init_user_ns) |
---|
| 291 | + rkey = request_key(&key_type_id_resolver, desc, ""); |
---|
282 | 292 | if (IS_ERR(rkey)) { |
---|
283 | 293 | mutex_lock(&idmap->idmap_mutex); |
---|
284 | 294 | rkey = request_key_with_auxdata(&key_type_id_resolver_legacy, |
---|
285 | | - desc, "", 0, idmap); |
---|
| 295 | + desc, NULL, "", 0, idmap); |
---|
286 | 296 | mutex_unlock(&idmap->idmap_mutex); |
---|
287 | 297 | } |
---|
288 | 298 | if (!IS_ERR(rkey)) |
---|
.. | .. |
---|
452 | 462 | if (idmap == NULL) |
---|
453 | 463 | return -ENOMEM; |
---|
454 | 464 | |
---|
| 465 | + mutex_init(&idmap->idmap_mutex); |
---|
| 466 | + idmap->user_ns = get_user_ns(clp->cl_rpcclient->cl_cred->user_ns); |
---|
| 467 | + |
---|
455 | 468 | rpc_init_pipe_dir_object(&idmap->idmap_pdo, |
---|
456 | 469 | &nfs_idmap_pipe_dir_object_ops, |
---|
457 | 470 | idmap); |
---|
.. | .. |
---|
462 | 475 | goto err; |
---|
463 | 476 | } |
---|
464 | 477 | idmap->idmap_pipe = pipe; |
---|
465 | | - mutex_init(&idmap->idmap_mutex); |
---|
466 | 478 | |
---|
467 | 479 | error = rpc_add_pipe_dir_object(clp->cl_net, |
---|
468 | 480 | &clp->cl_rpcclient->cl_pipedir_objects, |
---|
.. | .. |
---|
475 | 487 | err_destroy_pipe: |
---|
476 | 488 | rpc_destroy_pipe_data(idmap->idmap_pipe); |
---|
477 | 489 | err: |
---|
| 490 | + put_user_ns(idmap->user_ns); |
---|
478 | 491 | kfree(idmap); |
---|
479 | 492 | return error; |
---|
480 | 493 | } |
---|
.. | .. |
---|
491 | 504 | &clp->cl_rpcclient->cl_pipedir_objects, |
---|
492 | 505 | &idmap->idmap_pdo); |
---|
493 | 506 | rpc_destroy_pipe_data(idmap->idmap_pipe); |
---|
| 507 | + put_user_ns(idmap->user_ns); |
---|
494 | 508 | kfree(idmap); |
---|
495 | 509 | } |
---|
496 | 510 | |
---|
.. | .. |
---|
507 | 521 | switch (token) { |
---|
508 | 522 | case Opt_find_uid: |
---|
509 | 523 | im->im_type = IDMAP_TYPE_USER; |
---|
510 | | - /* Fall through */ |
---|
| 524 | + fallthrough; |
---|
511 | 525 | case Opt_find_gid: |
---|
512 | 526 | im->im_conv = IDMAP_CONV_NAMETOID; |
---|
513 | 527 | ret = match_strlcpy(im->im_name, &substr, IDMAP_NAMESZ); |
---|
.. | .. |
---|
515 | 529 | |
---|
516 | 530 | case Opt_find_user: |
---|
517 | 531 | im->im_type = IDMAP_TYPE_USER; |
---|
518 | | - /* Fall through */ |
---|
| 532 | + fallthrough; |
---|
519 | 533 | case Opt_find_group: |
---|
520 | 534 | im->im_conv = IDMAP_CONV_IDTONAME; |
---|
521 | 535 | ret = match_int(&substr, &im->im_id); |
---|
.. | .. |
---|
547 | 561 | return true; |
---|
548 | 562 | } |
---|
549 | 563 | |
---|
550 | | -static void |
---|
551 | | -nfs_idmap_complete_pipe_upcall_locked(struct idmap *idmap, int ret) |
---|
| 564 | +static void nfs_idmap_complete_pipe_upcall(struct idmap_legacy_upcalldata *data, |
---|
| 565 | + int ret) |
---|
552 | 566 | { |
---|
553 | | - struct key *authkey = idmap->idmap_upcall_data->authkey; |
---|
554 | | - |
---|
555 | | - kfree(idmap->idmap_upcall_data); |
---|
556 | | - idmap->idmap_upcall_data = NULL; |
---|
557 | | - complete_request_key(authkey, ret); |
---|
558 | | - key_put(authkey); |
---|
| 567 | + complete_request_key(data->authkey, ret); |
---|
| 568 | + key_put(data->authkey); |
---|
| 569 | + kfree(data); |
---|
559 | 570 | } |
---|
560 | 571 | |
---|
561 | | -static void |
---|
562 | | -nfs_idmap_abort_pipe_upcall(struct idmap *idmap, int ret) |
---|
| 572 | +static void nfs_idmap_abort_pipe_upcall(struct idmap *idmap, |
---|
| 573 | + struct idmap_legacy_upcalldata *data, |
---|
| 574 | + int ret) |
---|
563 | 575 | { |
---|
564 | | - if (idmap->idmap_upcall_data != NULL) |
---|
565 | | - nfs_idmap_complete_pipe_upcall_locked(idmap, ret); |
---|
| 576 | + if (cmpxchg(&idmap->idmap_upcall_data, data, NULL) == data) |
---|
| 577 | + nfs_idmap_complete_pipe_upcall(data, ret); |
---|
566 | 578 | } |
---|
567 | 579 | |
---|
568 | 580 | static int nfs_idmap_legacy_upcall(struct key *authkey, void *aux) |
---|
.. | .. |
---|
599 | 611 | |
---|
600 | 612 | ret = rpc_queue_upcall(idmap->idmap_pipe, msg); |
---|
601 | 613 | if (ret < 0) |
---|
602 | | - nfs_idmap_abort_pipe_upcall(idmap, ret); |
---|
| 614 | + nfs_idmap_abort_pipe_upcall(idmap, data, ret); |
---|
603 | 615 | |
---|
604 | 616 | return ret; |
---|
605 | 617 | out2: |
---|
.. | .. |
---|
655 | 667 | struct request_key_auth *rka; |
---|
656 | 668 | struct rpc_inode *rpci = RPC_I(file_inode(filp)); |
---|
657 | 669 | struct idmap *idmap = (struct idmap *)rpci->private; |
---|
| 670 | + struct idmap_legacy_upcalldata *data; |
---|
658 | 671 | struct key *authkey; |
---|
659 | 672 | struct idmap_msg im; |
---|
660 | 673 | size_t namelen_in; |
---|
.. | .. |
---|
664 | 677 | * will have been woken up and someone else may now have used |
---|
665 | 678 | * idmap_key_cons - so after this point we may no longer touch it. |
---|
666 | 679 | */ |
---|
667 | | - if (idmap->idmap_upcall_data == NULL) |
---|
| 680 | + data = xchg(&idmap->idmap_upcall_data, NULL); |
---|
| 681 | + if (data == NULL) |
---|
668 | 682 | goto out_noupcall; |
---|
669 | 683 | |
---|
670 | | - authkey = idmap->idmap_upcall_data->authkey; |
---|
| 684 | + authkey = data->authkey; |
---|
671 | 685 | rka = get_request_key_auth(authkey); |
---|
672 | 686 | |
---|
673 | 687 | if (mlen != sizeof(im)) { |
---|
.. | .. |
---|
689 | 703 | if (namelen_in == 0 || namelen_in == IDMAP_NAMESZ) { |
---|
690 | 704 | ret = -EINVAL; |
---|
691 | 705 | goto out; |
---|
692 | | -} |
---|
| 706 | + } |
---|
693 | 707 | |
---|
694 | | - ret = nfs_idmap_read_and_verify_message(&im, |
---|
695 | | - &idmap->idmap_upcall_data->idmap_msg, |
---|
696 | | - rka->target_key, authkey); |
---|
| 708 | + ret = nfs_idmap_read_and_verify_message(&im, &data->idmap_msg, |
---|
| 709 | + rka->target_key, authkey); |
---|
697 | 710 | if (ret >= 0) { |
---|
698 | 711 | key_set_timeout(rka->target_key, nfs_idmap_cache_timeout); |
---|
699 | 712 | ret = mlen; |
---|
700 | 713 | } |
---|
701 | 714 | |
---|
702 | 715 | out: |
---|
703 | | - nfs_idmap_complete_pipe_upcall_locked(idmap, ret); |
---|
| 716 | + nfs_idmap_complete_pipe_upcall(data, ret); |
---|
704 | 717 | out_noupcall: |
---|
705 | 718 | return ret; |
---|
706 | 719 | } |
---|
.. | .. |
---|
714 | 727 | struct idmap *idmap = data->idmap; |
---|
715 | 728 | |
---|
716 | 729 | if (msg->errno) |
---|
717 | | - nfs_idmap_abort_pipe_upcall(idmap, msg->errno); |
---|
| 730 | + nfs_idmap_abort_pipe_upcall(idmap, data, msg->errno); |
---|
718 | 731 | } |
---|
719 | 732 | |
---|
720 | 733 | static void |
---|
.. | .. |
---|
722 | 735 | { |
---|
723 | 736 | struct rpc_inode *rpci = RPC_I(inode); |
---|
724 | 737 | struct idmap *idmap = (struct idmap *)rpci->private; |
---|
| 738 | + struct idmap_legacy_upcalldata *data; |
---|
725 | 739 | |
---|
726 | | - nfs_idmap_abort_pipe_upcall(idmap, -EPIPE); |
---|
| 740 | + data = xchg(&idmap->idmap_upcall_data, NULL); |
---|
| 741 | + if (data) |
---|
| 742 | + nfs_idmap_complete_pipe_upcall(data, -EPIPE); |
---|
727 | 743 | } |
---|
728 | 744 | |
---|
729 | 745 | int nfs_map_name_to_uid(const struct nfs_server *server, const char *name, size_t namelen, kuid_t *uid) |
---|
.. | .. |
---|
735 | 751 | if (!nfs_map_string_to_numeric(name, namelen, &id)) |
---|
736 | 752 | ret = nfs_idmap_lookup_id(name, namelen, "uid", &id, idmap); |
---|
737 | 753 | if (ret == 0) { |
---|
738 | | - *uid = make_kuid(&init_user_ns, id); |
---|
| 754 | + *uid = make_kuid(idmap_userns(idmap), id); |
---|
739 | 755 | if (!uid_valid(*uid)) |
---|
740 | 756 | ret = -ERANGE; |
---|
741 | 757 | } |
---|
.. | .. |
---|
752 | 768 | if (!nfs_map_string_to_numeric(name, namelen, &id)) |
---|
753 | 769 | ret = nfs_idmap_lookup_id(name, namelen, "gid", &id, idmap); |
---|
754 | 770 | if (ret == 0) { |
---|
755 | | - *gid = make_kgid(&init_user_ns, id); |
---|
| 771 | + *gid = make_kgid(idmap_userns(idmap), id); |
---|
756 | 772 | if (!gid_valid(*gid)) |
---|
757 | 773 | ret = -ERANGE; |
---|
758 | 774 | } |
---|
.. | .. |
---|
766 | 782 | int ret = -EINVAL; |
---|
767 | 783 | __u32 id; |
---|
768 | 784 | |
---|
769 | | - id = from_kuid(&init_user_ns, uid); |
---|
| 785 | + id = from_kuid_munged(idmap_userns(idmap), uid); |
---|
770 | 786 | if (!(server->caps & NFS_CAP_UIDGID_NOMAP)) |
---|
771 | 787 | ret = nfs_idmap_lookup_name(id, "user", buf, buflen, idmap); |
---|
772 | 788 | if (ret < 0) |
---|
.. | .. |
---|
780 | 796 | int ret = -EINVAL; |
---|
781 | 797 | __u32 id; |
---|
782 | 798 | |
---|
783 | | - id = from_kgid(&init_user_ns, gid); |
---|
| 799 | + id = from_kgid_munged(idmap_userns(idmap), gid); |
---|
784 | 800 | if (!(server->caps & NFS_CAP_UIDGID_NOMAP)) |
---|
785 | 801 | ret = nfs_idmap_lookup_name(id, "group", buf, buflen, idmap); |
---|
786 | 802 | if (ret < 0) |
---|