| .. | .. |
|---|
| 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) |
|---|