From 4175f29e62ca065acf2527eaaa81e6d9357f6fa5 Mon Sep 17 00:00:00 2001 From: James Peach Date: Thu, 17 Jan 2019 14:17:54 -0800 Subject: [PATCH] unshare: add --map-current-user option 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 --- sys-utils/unshare.1 | 7 ++++++- sys-utils/unshare.c | 50 +++++++++++++++++++++++++++++++++++++-------- 2 files changed, 47 insertions(+), 10 deletions(-) diff --git a/sys-utils/unshare.1 b/sys-utils/unshare.1 index d2ba6c3a5c..db8915fe9e 100644 --- a/sys-utils/unshare.1 +++ b/sys-utils/unshare.1 @@ -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 diff --git a/sys-utils/unshare.c b/sys-utils/unshare.c index 21910a4ee8..f32e4294c5 100644 --- a/sys-utils/unshare.c +++ b/sys-utils/unshare.c @@ -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 \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[=] 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); -- 2.47.3