summaryrefslogtreecommitdiffstats
path: root/sys-utils/unshare.c
diff options
context:
space:
mode:
authorLubomir Rintel2013-12-27 22:14:48 +0100
committerKarel Zak2014-01-07 11:04:42 +0100
commit4da21e374e34350941d54f7b0fe33a06d92e9eaa (patch)
treef21cdca14733c9c17c222c0b8b5f3f3129c7baa4 /sys-utils/unshare.c
parentcal: in man page improve grammar and wording of the reformation limitation (diff)
downloadkernel-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.c36
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))