unshare: allow custom uid/gid mappings in userns
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>
This commit is contained in:
parent
ea4dcdc788
commit
6e837b5a38
|
@ -169,6 +169,16 @@ implies creating a new mount namespace since the /proc mount would otherwise
|
|||
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
|
||||
|
@ -177,11 +187,13 @@ namespaces (such as configuring interfaces in the network namespace or mounting
|
|||
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.
|
||||
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
|
||||
|
|
|
@ -77,12 +77,6 @@ enum {
|
|||
SETGROUPS_ALLOW = 1,
|
||||
};
|
||||
|
||||
enum {
|
||||
MAP_USER_NONE,
|
||||
MAP_USER_ROOT,
|
||||
MAP_USER_CURRENT,
|
||||
};
|
||||
|
||||
static const char *setgroups_strings[] =
|
||||
{
|
||||
[SETGROUPS_DENY] = "deny",
|
||||
|
@ -288,6 +282,8 @@ static void __attribute__((__noreturn__)) usage(void)
|
|||
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);
|
||||
|
@ -323,6 +319,8 @@ int main(int argc, char *argv[])
|
|||
OPT_KEEPCAPS,
|
||||
OPT_MONOTONIC,
|
||||
OPT_BOOTTIME,
|
||||
OPT_MAPUSER,
|
||||
OPT_MAPGROUP,
|
||||
};
|
||||
static const struct option longopts[] = {
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
|
@ -340,6 +338,8 @@ int main(int argc, char *argv[])
|
|||
{ "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 },
|
||||
|
@ -356,7 +356,9 @@ int main(int argc, char *argv[])
|
|||
|
||||
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;
|
||||
|
@ -428,21 +430,23 @@ int main(int argc, char *argv[])
|
|||
unshare_flags |= CLONE_NEWNS;
|
||||
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"));
|
||||
|
||||
case OPT_MAPUSER:
|
||||
unshare_flags |= CLONE_NEWUSER;
|
||||
mapuser = MAP_USER_ROOT;
|
||||
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;
|
||||
case 'r':
|
||||
unshare_flags |= CLONE_NEWUSER;
|
||||
mapuser = 0;
|
||||
mapgroup = 0;
|
||||
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;
|
||||
mapuser = MAP_USER_CURRENT;
|
||||
mapuser = real_euid;
|
||||
mapgroup = real_egid;
|
||||
break;
|
||||
case OPT_SETGROUPS:
|
||||
setgrpcmd = setgroups_str2id(optarg);
|
||||
|
@ -561,33 +565,23 @@ 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 (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. */
|
||||
switch (mapuser) {
|
||||
case MAP_USER_ROOT:
|
||||
if (mapgroup != (gid_t) -1) {
|
||||
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);
|
||||
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);
|
||||
|
|
Loading…
Reference in New Issue