]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
unshare: add --map-current-user option
authorJames Peach <jpeach@apache.org>
Thu, 17 Jan 2019 22:17:54 +0000 (14:17 -0800)
committerJames Peach <jpeach@apache.org>
Sun, 8 Sep 2019 22:00:00 +0000 (15:00 -0700)
Add the --map-current-user option to unshare. This option maps the
current effective UID and GID in the new user namespace so that the
inner and outer credentials match.

Signed-off-by: James Peach <jpeach@apache.org>
sys-utils/unshare.1
sys-utils/unshare.c

index d2ba6c3a5cadbb259e9a434216de7ced91c831e4..db8915fe9ec4b9d89375e37c90ea94a761fdc555 100644 (file)
@@ -159,7 +159,12 @@ conveniently gain capabilities needed to manage various aspects of the newly cre
 namespaces (such as configuring interfaces in the network namespace or mounting filesystems in
 the mount namespace) even when run unprivileged.  As a mere convenience feature, it does not support
 more sophisticated use cases, such as mapping multiple ranges of UIDs and GIDs.
-This option implies \fB--setgroups=deny\fR.
+This option implies \fB--setgroups=deny\fR and \fB--user\fR.
+.TP
+.BR \-c , " \-\-map\-current\-user"
+Run the program only after the current effective user and group IDs have been mapped to
+the same UID and GID in the newly created user namespace. This option implies
+\fB--setgroups=deny\fR and \fB--user\fR.
 .TP
 .BR "\-\-propagation private" | shared | slave | unchanged
 Recursively set the mount propagation flag in the new mount namespace.  The default
index 21910a4ee8c94616a22b9ec866d9d7e73770a289..f32e4294c5ec90025d615874d11625748004fd59 100644 (file)
@@ -76,6 +76,12 @@ enum {
        SETGROUPS_ALLOW = 1,
 };
 
+enum {
+       MAP_USER_NONE,
+       MAP_USER_ROOT,
+       MAP_USER_CURRENT,
+};
+
 static const char *setgroups_strings[] =
 {
        [SETGROUPS_DENY] = "deny",
@@ -264,6 +270,7 @@ static void __attribute__((__noreturn__)) usage(void)
        fputs(USAGE_SEPARATOR, out);
        fputs(_(" -f, --fork                fork before launching <program>\n"), out);
        fputs(_(" -r, --map-root-user       map current user to root (implies --user)\n"), out);
+       fputs(_(" -c, --map-current-user    map current user to itself (implies --user)\n"), out);
        fputs(USAGE_SEPARATOR, out);
        fputs(_(" --kill-child[=<signame>]  when dying, kill the forked child (implies --fork)\n"
                "                             defaults to SIGKILL\n"), out);
@@ -308,6 +315,7 @@ int main(int argc, char *argv[])
                { "kill-child",    optional_argument, NULL, OPT_KILLCHILD   },
                { "mount-proc",    optional_argument, NULL, OPT_MOUNTPROC   },
                { "map-root-user", no_argument,       NULL, 'r'             },
+               { "map-current-user", no_argument,    NULL, 'c'             },
                { "propagation",   required_argument, NULL, OPT_PROPAGATION },
                { "setgroups",     required_argument, NULL, OPT_SETGROUPS   },
                { "setuid",        required_argument, NULL, 'S'             },
@@ -319,7 +327,7 @@ int main(int argc, char *argv[])
 
        int setgrpcmd = SETGROUPS_NONE;
        int unshare_flags = 0;
-       int c, forkit = 0, maproot = 0;
+       int c, forkit = 0, mapuser = MAP_USER_NONE;
        int kill_child_signo = 0; /* 0 means --kill-child was not used */
        const char *procmnt = NULL;
        const char *newroot = NULL;
@@ -382,8 +390,20 @@ int main(int argc, char *argv[])
                        procmnt = optarg ? optarg : "/proc";
                        break;
                case 'r':
+                       if (mapuser == MAP_USER_CURRENT)
+                               errx(EXIT_FAILURE, _("options --map-root-user and "
+                                       "--map-current-user are mutually exclusive"));
+
+                       unshare_flags |= CLONE_NEWUSER;
+                       mapuser = MAP_USER_ROOT;
+                       break;
+               case 'c':
+                       if (mapuser == MAP_USER_ROOT)
+                               errx(EXIT_FAILURE, _("options --map-root-user and "
+                                       "--map-current-user are mutually exclusive"));
+
                        unshare_flags |= CLONE_NEWUSER;
-                       maproot = 1;
+                       mapuser = MAP_USER_CURRENT;
                        break;
                case OPT_SETGROUPS:
                        setgrpcmd = setgroups_str2id(optarg);
@@ -480,21 +500,33 @@ int main(int argc, char *argv[])
        if (kill_child_signo != 0 && prctl(PR_SET_PDEATHSIG, kill_child_signo) < 0)
                err(EXIT_FAILURE, "prctl failed");
 
-       if (maproot) {
+        /* Since Linux 3.19 unprivileged writing of /proc/self/gid_map
+         * has been disabled unless /proc/self/setgroups is written
+         * first to permanently disable the ability to call setgroups
+         * in that user namespace. */
+        switch (mapuser) {
+        case MAP_USER_ROOT:
                if (setgrpcmd == SETGROUPS_ALLOW)
                        errx(EXIT_FAILURE, _("options --setgroups=allow and "
                                        "--map-root-user are mutually exclusive"));
 
-               /* since Linux 3.19 unprivileged writing of /proc/self/gid_map
-                * has s been disabled unless /proc/self/setgroups is written
-                * first to permanently disable the ability to call setgroups
-                * in that user namespace. */
                setgroups_control(SETGROUPS_DENY);
                map_id(_PATH_PROC_UIDMAP, 0, real_euid);
                map_id(_PATH_PROC_GIDMAP, 0, real_egid);
+                break;
+        case MAP_USER_CURRENT:
+               if (setgrpcmd == SETGROUPS_ALLOW)
+                       errx(EXIT_FAILURE, _("options --setgroups=allow and "
+                                       "--map-current-user are mutually exclusive"));
 
-       } else if (setgrpcmd != SETGROUPS_NONE)
-               setgroups_control(setgrpcmd);
+               setgroups_control(SETGROUPS_DENY);
+               map_id(_PATH_PROC_UIDMAP, real_euid, real_euid);
+               map_id(_PATH_PROC_GIDMAP, real_egid, real_egid);
+                break;
+        case MAP_USER_NONE:
+               if (setgrpcmd != SETGROUPS_NONE)
+                       setgroups_control(setgrpcmd);
+        }
 
        if ((unshare_flags & CLONE_NEWNS) && propagation)
                set_propagation(propagation);