diff options
Diffstat (limited to 'fs/nfs/idmap.c')
-rw-r--r-- | fs/nfs/idmap.c | 114 |
1 files changed, 74 insertions, 40 deletions
diff --git a/fs/nfs/idmap.c b/fs/nfs/idmap.c index a850079467d8..9cc4a3fbf4b0 100644 --- a/fs/nfs/idmap.c +++ b/fs/nfs/idmap.c | |||
@@ -55,18 +55,19 @@ | |||
55 | static const struct cred *id_resolver_cache; | 55 | static const struct cred *id_resolver_cache; |
56 | static struct key_type key_type_id_resolver_legacy; | 56 | static struct key_type key_type_id_resolver_legacy; |
57 | 57 | ||
58 | struct idmap { | ||
59 | struct rpc_pipe *idmap_pipe; | ||
60 | struct key_construction *idmap_key_cons; | ||
61 | struct mutex idmap_mutex; | ||
62 | }; | ||
63 | |||
64 | struct idmap_legacy_upcalldata { | 58 | struct idmap_legacy_upcalldata { |
65 | struct rpc_pipe_msg pipe_msg; | 59 | struct rpc_pipe_msg pipe_msg; |
66 | struct idmap_msg idmap_msg; | 60 | struct idmap_msg idmap_msg; |
61 | struct key_construction *key_cons; | ||
67 | struct idmap *idmap; | 62 | struct idmap *idmap; |
68 | }; | 63 | }; |
69 | 64 | ||
65 | struct idmap { | ||
66 | struct rpc_pipe *idmap_pipe; | ||
67 | struct idmap_legacy_upcalldata *idmap_upcall_data; | ||
68 | struct mutex idmap_mutex; | ||
69 | }; | ||
70 | |||
70 | /** | 71 | /** |
71 | * nfs_fattr_init_names - initialise the nfs_fattr owner_name/group_name fields | 72 | * nfs_fattr_init_names - initialise the nfs_fattr owner_name/group_name fields |
72 | * @fattr: fully initialised struct nfs_fattr | 73 | * @fattr: fully initialised struct nfs_fattr |
@@ -158,7 +159,7 @@ static int nfs_map_string_to_numeric(const char *name, size_t namelen, __u32 *re | |||
158 | return 0; | 159 | return 0; |
159 | memcpy(buf, name, namelen); | 160 | memcpy(buf, name, namelen); |
160 | buf[namelen] = '\0'; | 161 | buf[namelen] = '\0'; |
161 | if (strict_strtoul(buf, 0, &val) != 0) | 162 | if (kstrtoul(buf, 0, &val) != 0) |
162 | return 0; | 163 | return 0; |
163 | *res = val; | 164 | *res = val; |
164 | return 1; | 165 | return 1; |
@@ -330,7 +331,6 @@ static ssize_t nfs_idmap_get_key(const char *name, size_t namelen, | |||
330 | ret = nfs_idmap_request_key(&key_type_id_resolver_legacy, | 331 | ret = nfs_idmap_request_key(&key_type_id_resolver_legacy, |
331 | name, namelen, type, data, | 332 | name, namelen, type, data, |
332 | data_size, idmap); | 333 | data_size, idmap); |
333 | idmap->idmap_key_cons = NULL; | ||
334 | mutex_unlock(&idmap->idmap_mutex); | 334 | mutex_unlock(&idmap->idmap_mutex); |
335 | } | 335 | } |
336 | return ret; | 336 | return ret; |
@@ -364,7 +364,7 @@ static int nfs_idmap_lookup_id(const char *name, size_t namelen, const char *typ | |||
364 | if (data_size <= 0) { | 364 | if (data_size <= 0) { |
365 | ret = -EINVAL; | 365 | ret = -EINVAL; |
366 | } else { | 366 | } else { |
367 | ret = strict_strtol(id_str, 10, &id_long); | 367 | ret = kstrtol(id_str, 10, &id_long); |
368 | *id = (__u32)id_long; | 368 | *id = (__u32)id_long; |
369 | } | 369 | } |
370 | return ret; | 370 | return ret; |
@@ -465,8 +465,6 @@ nfs_idmap_new(struct nfs_client *clp) | |||
465 | struct rpc_pipe *pipe; | 465 | struct rpc_pipe *pipe; |
466 | int error; | 466 | int error; |
467 | 467 | ||
468 | BUG_ON(clp->cl_idmap != NULL); | ||
469 | |||
470 | idmap = kzalloc(sizeof(*idmap), GFP_KERNEL); | 468 | idmap = kzalloc(sizeof(*idmap), GFP_KERNEL); |
471 | if (idmap == NULL) | 469 | if (idmap == NULL) |
472 | return -ENOMEM; | 470 | return -ENOMEM; |
@@ -510,7 +508,6 @@ static int __rpc_pipefs_event(struct nfs_client *clp, unsigned long event, | |||
510 | 508 | ||
511 | switch (event) { | 509 | switch (event) { |
512 | case RPC_PIPEFS_MOUNT: | 510 | case RPC_PIPEFS_MOUNT: |
513 | BUG_ON(clp->cl_rpcclient->cl_dentry == NULL); | ||
514 | err = __nfs_idmap_register(clp->cl_rpcclient->cl_dentry, | 511 | err = __nfs_idmap_register(clp->cl_rpcclient->cl_dentry, |
515 | clp->cl_idmap, | 512 | clp->cl_idmap, |
516 | clp->cl_idmap->idmap_pipe); | 513 | clp->cl_idmap->idmap_pipe); |
@@ -632,9 +629,6 @@ static int nfs_idmap_prepare_message(char *desc, struct idmap *idmap, | |||
632 | substring_t substr; | 629 | substring_t substr; |
633 | int token, ret; | 630 | int token, ret; |
634 | 631 | ||
635 | memset(im, 0, sizeof(*im)); | ||
636 | memset(msg, 0, sizeof(*msg)); | ||
637 | |||
638 | im->im_type = IDMAP_TYPE_GROUP; | 632 | im->im_type = IDMAP_TYPE_GROUP; |
639 | token = match_token(desc, nfs_idmap_tokens, &substr); | 633 | token = match_token(desc, nfs_idmap_tokens, &substr); |
640 | 634 | ||
@@ -665,6 +659,35 @@ out: | |||
665 | return ret; | 659 | return ret; |
666 | } | 660 | } |
667 | 661 | ||
662 | static bool | ||
663 | nfs_idmap_prepare_pipe_upcall(struct idmap *idmap, | ||
664 | struct idmap_legacy_upcalldata *data) | ||
665 | { | ||
666 | if (idmap->idmap_upcall_data != NULL) { | ||
667 | WARN_ON_ONCE(1); | ||
668 | return false; | ||
669 | } | ||
670 | idmap->idmap_upcall_data = data; | ||
671 | return true; | ||
672 | } | ||
673 | |||
674 | static void | ||
675 | nfs_idmap_complete_pipe_upcall_locked(struct idmap *idmap, int ret) | ||
676 | { | ||
677 | struct key_construction *cons = idmap->idmap_upcall_data->key_cons; | ||
678 | |||
679 | kfree(idmap->idmap_upcall_data); | ||
680 | idmap->idmap_upcall_data = NULL; | ||
681 | complete_request_key(cons, ret); | ||
682 | } | ||
683 | |||
684 | static void | ||
685 | nfs_idmap_abort_pipe_upcall(struct idmap *idmap, int ret) | ||
686 | { | ||
687 | if (idmap->idmap_upcall_data != NULL) | ||
688 | nfs_idmap_complete_pipe_upcall_locked(idmap, ret); | ||
689 | } | ||
690 | |||
668 | static int nfs_idmap_legacy_upcall(struct key_construction *cons, | 691 | static int nfs_idmap_legacy_upcall(struct key_construction *cons, |
669 | const char *op, | 692 | const char *op, |
670 | void *aux) | 693 | void *aux) |
@@ -677,29 +700,28 @@ static int nfs_idmap_legacy_upcall(struct key_construction *cons, | |||
677 | int ret = -ENOMEM; | 700 | int ret = -ENOMEM; |
678 | 701 | ||
679 | /* msg and im are freed in idmap_pipe_destroy_msg */ | 702 | /* msg and im are freed in idmap_pipe_destroy_msg */ |
680 | data = kmalloc(sizeof(*data), GFP_KERNEL); | 703 | data = kzalloc(sizeof(*data), GFP_KERNEL); |
681 | if (!data) | 704 | if (!data) |
682 | goto out1; | 705 | goto out1; |
683 | 706 | ||
684 | msg = &data->pipe_msg; | 707 | msg = &data->pipe_msg; |
685 | im = &data->idmap_msg; | 708 | im = &data->idmap_msg; |
686 | data->idmap = idmap; | 709 | data->idmap = idmap; |
710 | data->key_cons = cons; | ||
687 | 711 | ||
688 | ret = nfs_idmap_prepare_message(key->description, idmap, im, msg); | 712 | ret = nfs_idmap_prepare_message(key->description, idmap, im, msg); |
689 | if (ret < 0) | 713 | if (ret < 0) |
690 | goto out2; | 714 | goto out2; |
691 | 715 | ||
692 | BUG_ON(idmap->idmap_key_cons != NULL); | 716 | ret = -EAGAIN; |
693 | idmap->idmap_key_cons = cons; | 717 | if (!nfs_idmap_prepare_pipe_upcall(idmap, data)) |
718 | goto out2; | ||
694 | 719 | ||
695 | ret = rpc_queue_upcall(idmap->idmap_pipe, msg); | 720 | ret = rpc_queue_upcall(idmap->idmap_pipe, msg); |
696 | if (ret < 0) | 721 | if (ret < 0) |
697 | goto out3; | 722 | nfs_idmap_abort_pipe_upcall(idmap, ret); |
698 | 723 | ||
699 | return ret; | 724 | return ret; |
700 | |||
701 | out3: | ||
702 | idmap->idmap_key_cons = NULL; | ||
703 | out2: | 725 | out2: |
704 | kfree(data); | 726 | kfree(data); |
705 | out1: | 727 | out1: |
@@ -714,21 +736,32 @@ static int nfs_idmap_instantiate(struct key *key, struct key *authkey, char *dat | |||
714 | authkey); | 736 | authkey); |
715 | } | 737 | } |
716 | 738 | ||
717 | static int nfs_idmap_read_message(struct idmap_msg *im, struct key *key, struct key *authkey) | 739 | static int nfs_idmap_read_and_verify_message(struct idmap_msg *im, |
740 | struct idmap_msg *upcall, | ||
741 | struct key *key, struct key *authkey) | ||
718 | { | 742 | { |
719 | char id_str[NFS_UINT_MAXLEN]; | 743 | char id_str[NFS_UINT_MAXLEN]; |
720 | int ret = -EINVAL; | 744 | int ret = -ENOKEY; |
721 | 745 | ||
746 | /* ret = -ENOKEY */ | ||
747 | if (upcall->im_type != im->im_type || upcall->im_conv != im->im_conv) | ||
748 | goto out; | ||
722 | switch (im->im_conv) { | 749 | switch (im->im_conv) { |
723 | case IDMAP_CONV_NAMETOID: | 750 | case IDMAP_CONV_NAMETOID: |
751 | if (strcmp(upcall->im_name, im->im_name) != 0) | ||
752 | break; | ||
724 | sprintf(id_str, "%d", im->im_id); | 753 | sprintf(id_str, "%d", im->im_id); |
725 | ret = nfs_idmap_instantiate(key, authkey, id_str); | 754 | ret = nfs_idmap_instantiate(key, authkey, id_str); |
726 | break; | 755 | break; |
727 | case IDMAP_CONV_IDTONAME: | 756 | case IDMAP_CONV_IDTONAME: |
757 | if (upcall->im_id != im->im_id) | ||
758 | break; | ||
728 | ret = nfs_idmap_instantiate(key, authkey, im->im_name); | 759 | ret = nfs_idmap_instantiate(key, authkey, im->im_name); |
729 | break; | 760 | break; |
761 | default: | ||
762 | ret = -EINVAL; | ||
730 | } | 763 | } |
731 | 764 | out: | |
732 | return ret; | 765 | return ret; |
733 | } | 766 | } |
734 | 767 | ||
@@ -740,14 +773,16 @@ idmap_pipe_downcall(struct file *filp, const char __user *src, size_t mlen) | |||
740 | struct key_construction *cons; | 773 | struct key_construction *cons; |
741 | struct idmap_msg im; | 774 | struct idmap_msg im; |
742 | size_t namelen_in; | 775 | size_t namelen_in; |
743 | int ret; | 776 | int ret = -ENOKEY; |
744 | 777 | ||
745 | /* If instantiation is successful, anyone waiting for key construction | 778 | /* If instantiation is successful, anyone waiting for key construction |
746 | * will have been woken up and someone else may now have used | 779 | * will have been woken up and someone else may now have used |
747 | * idmap_key_cons - so after this point we may no longer touch it. | 780 | * idmap_key_cons - so after this point we may no longer touch it. |
748 | */ | 781 | */ |
749 | cons = ACCESS_ONCE(idmap->idmap_key_cons); | 782 | if (idmap->idmap_upcall_data == NULL) |
750 | idmap->idmap_key_cons = NULL; | 783 | goto out_noupcall; |
784 | |||
785 | cons = idmap->idmap_upcall_data->key_cons; | ||
751 | 786 | ||
752 | if (mlen != sizeof(im)) { | 787 | if (mlen != sizeof(im)) { |
753 | ret = -ENOSPC; | 788 | ret = -ENOSPC; |
@@ -768,16 +803,19 @@ idmap_pipe_downcall(struct file *filp, const char __user *src, size_t mlen) | |||
768 | if (namelen_in == 0 || namelen_in == IDMAP_NAMESZ) { | 803 | if (namelen_in == 0 || namelen_in == IDMAP_NAMESZ) { |
769 | ret = -EINVAL; | 804 | ret = -EINVAL; |
770 | goto out; | 805 | goto out; |
771 | } | 806 | } |
772 | 807 | ||
773 | ret = nfs_idmap_read_message(&im, cons->key, cons->authkey); | 808 | ret = nfs_idmap_read_and_verify_message(&im, |
809 | &idmap->idmap_upcall_data->idmap_msg, | ||
810 | cons->key, cons->authkey); | ||
774 | if (ret >= 0) { | 811 | if (ret >= 0) { |
775 | key_set_timeout(cons->key, nfs_idmap_cache_timeout); | 812 | key_set_timeout(cons->key, nfs_idmap_cache_timeout); |
776 | ret = mlen; | 813 | ret = mlen; |
777 | } | 814 | } |
778 | 815 | ||
779 | out: | 816 | out: |
780 | complete_request_key(cons, ret); | 817 | nfs_idmap_complete_pipe_upcall_locked(idmap, ret); |
818 | out_noupcall: | ||
781 | return ret; | 819 | return ret; |
782 | } | 820 | } |
783 | 821 | ||
@@ -788,14 +826,9 @@ idmap_pipe_destroy_msg(struct rpc_pipe_msg *msg) | |||
788 | struct idmap_legacy_upcalldata, | 826 | struct idmap_legacy_upcalldata, |
789 | pipe_msg); | 827 | pipe_msg); |
790 | struct idmap *idmap = data->idmap; | 828 | struct idmap *idmap = data->idmap; |
791 | struct key_construction *cons; | 829 | |
792 | if (msg->errno) { | 830 | if (msg->errno) |
793 | cons = ACCESS_ONCE(idmap->idmap_key_cons); | 831 | nfs_idmap_abort_pipe_upcall(idmap, msg->errno); |
794 | idmap->idmap_key_cons = NULL; | ||
795 | complete_request_key(cons, msg->errno); | ||
796 | } | ||
797 | /* Free memory allocated in nfs_idmap_legacy_upcall() */ | ||
798 | kfree(data); | ||
799 | } | 832 | } |
800 | 833 | ||
801 | static void | 834 | static void |
@@ -803,7 +836,8 @@ idmap_release_pipe(struct inode *inode) | |||
803 | { | 836 | { |
804 | struct rpc_inode *rpci = RPC_I(inode); | 837 | struct rpc_inode *rpci = RPC_I(inode); |
805 | struct idmap *idmap = (struct idmap *)rpci->private; | 838 | struct idmap *idmap = (struct idmap *)rpci->private; |
806 | idmap->idmap_key_cons = NULL; | 839 | |
840 | nfs_idmap_abort_pipe_upcall(idmap, -EPIPE); | ||
807 | } | 841 | } |
808 | 842 | ||
809 | int nfs_map_name_to_uid(const struct nfs_server *server, const char *name, size_t namelen, __u32 *uid) | 843 | int nfs_map_name_to_uid(const struct nfs_server *server, const char *name, size_t namelen, __u32 *uid) |