Two new options are added: `--map-user=<uid>` and `--map-group=<gid>`
for custom user and group mappings respectively. These are just
generalizations of the existing `--map-root-user` and
`--map-current-user` options.
As a side effect of this commit, specifying both `--map-root-user` and
`--map-current-user` no longer causes an error. Instead, the last
occurrence takes precedence.
Addresses: https://github.com/karelzak/util-linux/issues/885
Signed-off-by: Matthew Harm Bekkema <id@mbekkema.name>
mess up existing programs on the system. The new proc filesystem is explicitly
mounted as private (with MS_PRIVATE|MS_REC).
.TP
mess up existing programs on the system. The new proc filesystem is explicitly
mounted as private (with MS_PRIVATE|MS_REC).
.TP
+.BR \-\-map\-user=\fIuid
+Run the program only after the current effective user ID has been mapped to \fIuid\fP.
+If this option is specified multiple times, the last occurrence takes precedence.
+This option implies \fB\-\-user\fR.
+.TP
+.BR \-\-map\-group=\fIgid
+Run the program only after the current effective group ID has been mapped to \fIgid\fP.
+If this option is specified multiple times, the last occurrence takes precedence.
+This option implies \fB\-\-setgroups=deny\fR and \fB\-\-user\fR.
+.TP
.BR \-r , " \-\-map\-root\-user"
Run the program only after the current effective user and group IDs have been mapped to
the superuser UID and GID in the newly created user namespace. This makes it possible to
.BR \-r , " \-\-map\-root\-user"
Run the program only after the current effective user and group IDs have been mapped to
the superuser UID and GID in the newly created user namespace. This makes it possible to
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 and \fB\-\-user\fR.
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 and \fB\-\-user\fR.
+This option is equivalent to \fB\-\-map-user=0 \-\-map-group=0\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 \-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.
+This option is equivalent to \fB\-\-map-user=$(id -ru) \-\-map-group=$(id -rg)\fR.
.TP
.BR "\-\-propagation private" | shared | slave | unchanged
Recursively set the mount propagation flag in the new mount namespace. The default
.TP
.BR "\-\-propagation private" | shared | slave | unchanged
Recursively set the mount propagation flag in the new mount namespace. The default
-enum {
- MAP_USER_NONE,
- MAP_USER_ROOT,
- MAP_USER_CURRENT,
-};
-
static const char *setgroups_strings[] =
{
[SETGROUPS_DENY] = "deny",
static const char *setgroups_strings[] =
{
[SETGROUPS_DENY] = "deny",
fputs(_(" -T, --time[=<file>] unshare time namespace\n"), out);
fputs(USAGE_SEPARATOR, out);
fputs(_(" -f, --fork fork before launching <program>\n"), out);
fputs(_(" -T, --time[=<file>] unshare time namespace\n"), out);
fputs(USAGE_SEPARATOR, out);
fputs(_(" -f, --fork fork before launching <program>\n"), out);
+ fputs(_(" --map-user=<uid> map current user to uid (implies --user)\n"), out);
+ fputs(_(" --map-group=<gid> map current group to gid (implies --user)\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(_(" -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);
OPT_KEEPCAPS,
OPT_MONOTONIC,
OPT_BOOTTIME,
OPT_KEEPCAPS,
OPT_MONOTONIC,
OPT_BOOTTIME,
+ OPT_MAPUSER,
+ OPT_MAPGROUP,
};
static const struct option longopts[] = {
{ "help", no_argument, NULL, 'h' },
};
static const struct option longopts[] = {
{ "help", no_argument, NULL, 'h' },
{ "fork", no_argument, NULL, 'f' },
{ "kill-child", optional_argument, NULL, OPT_KILLCHILD },
{ "mount-proc", optional_argument, NULL, OPT_MOUNTPROC },
{ "fork", no_argument, NULL, 'f' },
{ "kill-child", optional_argument, NULL, OPT_KILLCHILD },
{ "mount-proc", optional_argument, NULL, OPT_MOUNTPROC },
+ { "map-user", required_argument, NULL, OPT_MAPUSER },
+ { "map-group", required_argument, NULL, OPT_MAPGROUP },
{ "map-root-user", no_argument, NULL, 'r' },
{ "map-current-user", no_argument, NULL, 'c' },
{ "propagation", required_argument, NULL, OPT_PROPAGATION },
{ "map-root-user", no_argument, NULL, 'r' },
{ "map-current-user", no_argument, NULL, 'c' },
{ "propagation", required_argument, NULL, OPT_PROPAGATION },
int setgrpcmd = SETGROUPS_NONE;
int unshare_flags = 0;
int setgrpcmd = SETGROUPS_NONE;
int unshare_flags = 0;
- int c, forkit = 0, mapuser = MAP_USER_NONE;
+ int c, forkit = 0;
+ uid_t mapuser = -1;
+ gid_t mapgroup = -1;
int kill_child_signo = 0; /* 0 means --kill-child was not used */
const char *procmnt = NULL;
const char *newroot = NULL;
int kill_child_signo = 0; /* 0 means --kill-child was not used */
const char *procmnt = NULL;
const char *newroot = NULL;
unshare_flags |= CLONE_NEWNS;
procmnt = optarg ? optarg : "/proc";
break;
unshare_flags |= CLONE_NEWNS;
procmnt = optarg ? optarg : "/proc";
break;
+ case OPT_MAPUSER:
+ unshare_flags |= CLONE_NEWUSER;
+ mapuser = strtoul_or_err(optarg, _("failed to parse uid"));
+ break;
+ case OPT_MAPGROUP:
+ unshare_flags |= CLONE_NEWUSER;
+ mapgroup = strtoul_or_err(optarg, _("failed to parse gid"));
+ break;
- if (mapuser == MAP_USER_CURRENT)
- errx(EXIT_FAILURE, _("options --map-root-user and "
- "--map-current-user are mutually exclusive"));
-
unshare_flags |= CLONE_NEWUSER;
unshare_flags |= CLONE_NEWUSER;
- mapuser = MAP_USER_ROOT;
+ mapuser = 0;
+ mapgroup = 0;
- if (mapuser == MAP_USER_ROOT)
- errx(EXIT_FAILURE, _("options --map-root-user and "
- "--map-current-user are mutually exclusive"));
-
unshare_flags |= CLONE_NEWUSER;
unshare_flags |= CLONE_NEWUSER;
- mapuser = MAP_USER_CURRENT;
+ mapuser = real_euid;
+ mapgroup = real_egid;
break;
case OPT_SETGROUPS:
setgrpcmd = setgroups_str2id(optarg);
break;
case OPT_SETGROUPS:
setgrpcmd = setgroups_str2id(optarg);
if (kill_child_signo != 0 && prctl(PR_SET_PDEATHSIG, kill_child_signo) < 0)
err(EXIT_FAILURE, "prctl failed");
if (kill_child_signo != 0 && prctl(PR_SET_PDEATHSIG, kill_child_signo) < 0)
err(EXIT_FAILURE, "prctl failed");
+ if (mapuser != (uid_t) -1)
+ map_id(_PATH_PROC_UIDMAP, mapuser, real_euid);
+
/* 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. */
/* 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 (mapgroup != (gid_t) -1) {
if (setgrpcmd == SETGROUPS_ALLOW)
errx(EXIT_FAILURE, _("options --setgroups=allow and "
if (setgrpcmd == SETGROUPS_ALLOW)
errx(EXIT_FAILURE, _("options --setgroups=allow and "
- "--map-root-user are mutually exclusive"));
-
+ "--map-group are mutually exclusive"));
setgroups_control(SETGROUPS_DENY);
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"));
+ map_id(_PATH_PROC_GIDMAP, mapgroup, real_egid);
+ }
- 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 (setgrpcmd != SETGROUPS_NONE)
+ setgroups_control(setgrpcmd);
if ((unshare_flags & CLONE_NEWNS) && propagation)
set_propagation(propagation);
if ((unshare_flags & CLONE_NEWNS) && propagation)
set_propagation(propagation);