diff options
author | Lubomir Rintel | 2013-12-27 22:14:48 +0100 |
---|---|---|
committer | Karel Zak | 2014-01-07 11:04:42 +0100 |
commit | 4da21e374e34350941d54f7b0fe33a06d92e9eaa (patch) | |
tree | f21cdca14733c9c17c222c0b8b5f3f3129c7baa4 /sys-utils/unshare.c | |
parent | cal: in man page improve grammar and wording of the reformation limitation (diff) | |
download | kernel-qcow2-util-linux-4da21e374e34350941d54f7b0fe33a06d92e9eaa.tar.gz kernel-qcow2-util-linux-4da21e374e34350941d54f7b0fe33a06d92e9eaa.tar.xz kernel-qcow2-util-linux-4da21e374e34350941d54f7b0fe33a06d92e9eaa.zip |
unshare: Add possibility to add mapping into root user in user namespace
This makes it very convenient to use make use of privileged actions
on CONFIG_USER_NS enabled kernels, without having to manually tinker
with uid_map and gid_map to obtain required credentials (as those
given upon unshare() vanish with call to execve() and lot of userspace
checks for euid==0 anyway).
Usage example:
$ unshare --uts
unshare: unshare failed: Operation not permitted
$ unshare --user --uts
[nfsnobody@odvarok ~]$ hostname swag
hostname: you must be root to change the host name
$ unshare -r --uts
[root@odvarok util-linux]# hostname swag
[root@odvarok util-linux]#
[kzak@redhat.com: - move code to map_id()
- use all-io.h
- add paths to pathnames.h]
Signed-off-by: Lubomir Rintel <lkundrak@v3.sk>
Signed-off-by: Karel Zak <kzak@redhat.com>
Diffstat (limited to 'sys-utils/unshare.c')
-rw-r--r-- | sys-utils/unshare.c | 36 |
1 files changed, 34 insertions, 2 deletions
diff --git a/sys-utils/unshare.c b/sys-utils/unshare.c index 114f17da0..91e0ec74a 100644 --- a/sys-utils/unshare.c +++ b/sys-utils/unshare.c @@ -32,6 +32,25 @@ #include "closestream.h" #include "namespace.h" #include "exec_shell.h" +#include "xalloc.h" +#include "pathnames.h" +#include "all-io.h" + +static void map_id(const char *file, uint32_t from, uint32_t to) +{ + char *buf; + int fd; + + fd = open(file, O_WRONLY); + if (fd < 0) + err(EXIT_FAILURE, _("cannot open %s"), file); + + xasprintf(&buf, "%u %u 1", from, to); + if (write_all(fd, buf, strlen(buf))) + err(EXIT_FAILURE, _("write failed %s"), file); + free(buf); + close(fd); +} static void usage(int status) { @@ -50,6 +69,7 @@ static void usage(int status) fputs(_(" -U, --user unshare user namespace\n"), out); fputs(_(" -f, --fork fork before launching <program>\n"), out); fputs(_(" --mount-proc[=<dir>] mount proc filesystem first (implies --mount)\n"), out); + fputs(_(" -r, --map-root-user map current user to root (implies --user)\n"), out); fputs(USAGE_SEPARATOR, out); fputs(USAGE_HELP, out); @@ -75,19 +95,22 @@ int main(int argc, char *argv[]) { "user", no_argument, 0, 'U' }, { "fork", no_argument, 0, 'f' }, { "mount-proc", optional_argument, 0, OPT_MOUNTPROC }, + { "map-root-user", no_argument, 0, 'r' }, { NULL, 0, 0, 0 } }; int unshare_flags = 0; - int c, forkit = 0; + int c, forkit = 0, maproot = 0; const char *procmnt = NULL; + uid_t real_euid = geteuid(); + gid_t real_egid = getegid();; setlocale(LC_ALL, ""); bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); atexit(close_stdout); - while ((c = getopt_long(argc, argv, "fhVmuinpU", longopts, NULL)) != -1) { + while ((c = getopt_long(argc, argv, "fhVmuinpUr", longopts, NULL)) != -1) { switch (c) { case 'f': forkit = 1; @@ -119,6 +142,10 @@ int main(int argc, char *argv[]) unshare_flags |= CLONE_NEWNS; procmnt = optarg ? optarg : "/proc"; break; + case 'r': + unshare_flags |= CLONE_NEWUSER; + maproot = 1; + break; default: usage(EXIT_FAILURE); } @@ -147,6 +174,11 @@ int main(int argc, char *argv[]) } } + if (maproot) { + map_id(_PATH_PROC_UIDMAP, 0, real_euid); + map_id(_PATH_PROC_GIDMAP, 0, real_egid); + } + if (procmnt && (mount("none", procmnt, NULL, MS_PRIVATE|MS_REC, NULL) != 0 || mount("proc", procmnt, "proc", MS_NOSUID|MS_NOEXEC|MS_NODEV, NULL) != 0)) |