|
50 | 50 | #include "utils.h" |
51 | 51 | #include "network.h" |
52 | 52 |
|
| 53 | +#define usernic_debug_stream(stream, format, ...) \ |
| 54 | + do { \ |
| 55 | + fprintf(stream, "%s: %d: %s: " format, __FILE__, __LINE__, \ |
| 56 | + __func__, __VA_ARGS__); \ |
| 57 | + } while (false) |
| 58 | + |
| 59 | +#define usernic_error(format, ...) usernic_debug_stream(stderr, format, __VA_ARGS__) |
| 60 | + |
53 | 61 | static void usage(char *me, bool fail) |
54 | 62 | { |
55 | 63 | fprintf(stderr, "Usage: %s lxcpath name pid type bridge nicname\n", me); |
@@ -670,68 +678,115 @@ static bool create_db_dir(char *fnam) |
670 | 678 | } |
671 | 679 |
|
672 | 680 | #define VETH_DEF_NAME "eth%d" |
673 | | - |
674 | 681 | static int rename_in_ns(int pid, char *oldname, char **newnamep) |
675 | 682 | { |
676 | | - int fd = -1, ofd = -1, ret, ifindex = -1; |
| 683 | + uid_t ruid, suid, euid; |
| 684 | + int fret = -1; |
| 685 | + int fd = -1, ifindex = -1, ofd = -1, ret; |
677 | 686 | bool grab_newname = false; |
678 | 687 |
|
679 | 688 | ofd = lxc_preserve_ns(getpid(), "net"); |
680 | 689 | if (ofd < 0) { |
681 | | - fprintf(stderr, "Failed opening network namespace path for '%d'.", getpid()); |
682 | | - return -1; |
| 690 | + usernic_error("Failed opening network namespace path for '%d'.", getpid()); |
| 691 | + return fret; |
683 | 692 | } |
684 | 693 |
|
685 | 694 | fd = lxc_preserve_ns(pid, "net"); |
686 | 695 | if (fd < 0) { |
687 | | - fprintf(stderr, "Failed opening network namespace path for '%d'.", pid); |
688 | | - return -1; |
| 696 | + usernic_error("Failed opening network namespace path for '%d'.", pid); |
| 697 | + goto do_partial_cleanup; |
| 698 | + } |
| 699 | + |
| 700 | + ret = getresuid(&ruid, &euid, &suid); |
| 701 | + if (ret < 0) { |
| 702 | + usernic_error("Failed to retrieve real, effective, and saved " |
| 703 | + "user IDs: %s\n", |
| 704 | + strerror(errno)); |
| 705 | + goto do_partial_cleanup; |
| 706 | + } |
| 707 | + |
| 708 | + ret = setns(fd, CLONE_NEWNET); |
| 709 | + close(fd); |
| 710 | + fd = -1; |
| 711 | + if (ret < 0) { |
| 712 | + usernic_error("Failed to setns() to the network namespace of " |
| 713 | + "the container with PID %d: %s.\n", |
| 714 | + pid, strerror(errno)); |
| 715 | + goto do_partial_cleanup; |
689 | 716 | } |
690 | 717 |
|
691 | | - if (setns(fd, 0) < 0) { |
692 | | - fprintf(stderr, "setns to container network namespace\n"); |
693 | | - goto out_err; |
| 718 | + ret = setresuid(ruid, ruid, 0); |
| 719 | + if (ret < 0) { |
| 720 | + usernic_error("Failed to drop privilege by setting effective " |
| 721 | + "user id and real user id to %d, and saved user " |
| 722 | + "ID to 0: %s.\n", |
| 723 | + ruid, strerror(errno)); |
| 724 | + // COMMENT(brauner): It's ok to jump to do_full_cleanup here |
| 725 | + // since setresuid() will succeed when trying to set real, |
| 726 | + // effective, and saved to values they currently have. |
| 727 | + goto do_full_cleanup; |
694 | 728 | } |
695 | | - close(fd); fd = -1; |
| 729 | + |
696 | 730 | if (!*newnamep) { |
697 | 731 | grab_newname = true; |
698 | 732 | *newnamep = VETH_DEF_NAME; |
699 | | - if (!(ifindex = if_nametoindex(oldname))) { |
700 | | - fprintf(stderr, "failed to get netdev index\n"); |
701 | | - goto out_err; |
| 733 | + |
| 734 | + ifindex = if_nametoindex(oldname); |
| 735 | + if (!ifindex) { |
| 736 | + usernic_error("Failed to get netdev index: %s.\n", strerror(errno)); |
| 737 | + goto do_full_cleanup; |
702 | 738 | } |
703 | 739 | } |
704 | | - if ((ret = lxc_netdev_rename_by_name(oldname, *newnamep)) < 0) { |
705 | | - fprintf(stderr, "Error %d renaming netdev %s to %s in container\n", ret, oldname, *newnamep); |
706 | | - goto out_err; |
| 740 | + |
| 741 | + ret = lxc_netdev_rename_by_name(oldname, *newnamep); |
| 742 | + if (ret < 0) { |
| 743 | + usernic_error("Error %d renaming netdev %s to %s in container.\n", ret, oldname, *newnamep); |
| 744 | + goto do_full_cleanup; |
707 | 745 | } |
| 746 | + |
708 | 747 | if (grab_newname) { |
709 | | - char ifname[IFNAMSIZ], *namep = ifname; |
| 748 | + char ifname[IFNAMSIZ]; |
| 749 | + char *namep = ifname; |
| 750 | + |
710 | 751 | if (!if_indextoname(ifindex, namep)) { |
711 | | - fprintf(stderr, "Failed to get new netdev name\n"); |
712 | | - goto out_err; |
| 752 | + usernic_error("Failed to get new netdev name: %s.\n", strerror(errno)); |
| 753 | + goto do_full_cleanup; |
713 | 754 | } |
| 755 | + |
714 | 756 | *newnamep = strdup(namep); |
715 | 757 | if (!*newnamep) |
716 | | - goto out_err; |
| 758 | + goto do_full_cleanup; |
717 | 759 | } |
718 | | - if (setns(ofd, 0) < 0) { |
719 | | - fprintf(stderr, "Error returning to original netns\n"); |
720 | | - close(ofd); |
721 | | - return -1; |
| 760 | + |
| 761 | + fret = 0; |
| 762 | + |
| 763 | +do_full_cleanup: |
| 764 | + ret = setresuid(ruid, euid, suid); |
| 765 | + if (ret < 0) { |
| 766 | + usernic_error("Failed to restore privilege by setting effective " |
| 767 | + "user id to %d, real user id to %d, and saved user " |
| 768 | + "ID to %d: %s.\n", |
| 769 | + ruid, euid, suid, strerror(errno)); |
| 770 | + fret = -1; |
| 771 | + // COMMENT(brauner): setns() should fail if setresuid() doesn't |
| 772 | + // succeed but there's no harm in falling through; keeps the |
| 773 | + // code cleaner. |
722 | 774 | } |
723 | | - close(ofd); |
724 | 775 |
|
725 | | - return 0; |
| 776 | + ret = setns(ofd, CLONE_NEWNET); |
| 777 | + if (ret < 0) { |
| 778 | + usernic_error("Failed to setns() to original network namespace " |
| 779 | + "of PID %d: %s.\n", |
| 780 | + ofd, strerror(errno)); |
| 781 | + fret = -1; |
| 782 | + } |
726 | 783 |
|
727 | | -out_err: |
728 | | - if (ofd >= 0) |
729 | | - close(ofd); |
730 | | - if (setns(ofd, 0) < 0) |
731 | | - fprintf(stderr, "Error returning to original network namespace\n"); |
| 784 | +do_partial_cleanup: |
732 | 785 | if (fd >= 0) |
733 | 786 | close(fd); |
734 | | - return -1; |
| 787 | + close(ofd); |
| 788 | + |
| 789 | + return fret; |
735 | 790 | } |
736 | 791 |
|
737 | 792 | /* |
|
0 commit comments