summaryrefslogtreecommitdiffstats
path: root/sys-utils
diff options
context:
space:
mode:
authorNeil Horman2012-12-28 17:22:18 +0100
committerKarel Zak2013-01-07 14:56:32 +0100
commit4bbe8099390d528018890efa914e268de3c4b44b (patch)
tree79201355c9ad29ff76cf5aa8ba11423bf1a76c78 /sys-utils
parentagetty: replace perms 660 to 620 (diff)
downloadkernel-qcow2-util-linux-4bbe8099390d528018890efa914e268de3c4b44b.tar.gz
kernel-qcow2-util-linux-4bbe8099390d528018890efa914e268de3c4b44b.tar.xz
kernel-qcow2-util-linux-4bbe8099390d528018890efa914e268de3c4b44b.zip
unshare: support the switching of namespaces
In addition to the unshare syscall, there exists the setns syscall, which allows processes to migrate to the namepsaces of other processes. Add this functionality into the unshare command, as they operate in a fairly simmilar fashion. Note: There was discussion of adding a path based namespace argument to unshare in the origional discussion thread, but I opted to leave that out as it didn't seem to fit in nicely with the current argument pattern. I figure we can always add that in later if we need to [kzak@redhat.com: - fix optional arguments - do not call unshare if no flag specified - use O_CLOEXEC - codding style cleanup] Signed-off-by: Neil Horman <nhorman@tuxdriver.com> CC: Karel Zak <kzak@redhat.com> Signed-off-by: Karel Zak <kzak@redhat.com>
Diffstat (limited to 'sys-utils')
-rw-r--r--sys-utils/Makemodule.am1
-rw-r--r--sys-utils/unshare.136
-rw-r--r--sys-utils/unshare.c75
3 files changed, 83 insertions, 29 deletions
diff --git a/sys-utils/Makemodule.am b/sys-utils/Makemodule.am
index 33112fb68..5636f70da 100644
--- a/sys-utils/Makemodule.am
+++ b/sys-utils/Makemodule.am
@@ -287,6 +287,7 @@ if BUILD_UNSHARE
usrbin_exec_PROGRAMS += unshare
dist_man_MANS += sys-utils/unshare.1
unshare_SOURCES = sys-utils/unshare.c
+unshare_LDADD = $(LDADD) libcommon.la
endif
if BUILD_ARCH
diff --git a/sys-utils/unshare.1 b/sys-utils/unshare.1
index 1325e3481..c37083d41 100644
--- a/sys-utils/unshare.1
+++ b/sys-utils/unshare.1
@@ -3,15 +3,15 @@
.\"
.TH UNSHARE 1 "October 2008" "util-linux" "User Commands"
.SH NAME
-unshare \- run program with some namespaces unshared from parent
+unshare \- run program with some namespaces unshared or changed from parent
.SH SYNOPSIS
.B unshare
.RI [ options ]
program
.RI [ arguments ]
.SH DESCRIPTION
-Unshares specified namespaces from parent process and then executes specified
-program. Unshareable namespaces are:
+Unshares or migrates specified namespaces from parent process and then executes specified
+program. Available namespaces are:
.TP
.BR "mount namespace"
mounting and unmounting filesystems will not affect rest of the system
@@ -33,31 +33,43 @@ etc. (\fBCLONE_NEWNET\fP flag).
.TP
See the \fBclone\fR(2) for exact semantics of the flags.
.SH OPTIONS
+Note when specifying the optional \fB<pid>\fP argument, the string of option,
+equal sign (=), and the pid must not contain any blanks or other white space.
+The correct form is for example --ipc=123 or -i=123.
.TP
.BR \-h , " \-\-help"
Print a help message,
.TP
-.BR \-m , " \-\-mount"
-Unshare the mount namespace,
+.BR \-m , " \-\-mount " \fI[=pid]\fP
+Unshare the mount namespace, or, when a pid is specified, migrate the mount
+namespace to the one attached to the specified pid.
.TP
-.BR \-u , " \-\-uts"
-Unshare the UTC namespace,
+.BR \-u , " \-\-uts " \fI[=pid]\fP
+Unshare the UTC namespace, or, when a pid is specified, migrate the uts
+namespace to the one attached to the specified pid
.TP
-.BR \-i , " \-\-ipc"
-Unshare the IPC namespace,
+.BR \-i , " \-\-ipc " \fI[=pid]\fP
+Unshare the IPC namespace, or, when a pid is specified, migrate the ipc
+namespace to the one attached to the specified pid
.TP
-.BR \-n , " \-\-net"
-Unshare the network namespace.
+.BR \-n , " \-\-net " \fI[=pid]\fP
+Unshare the network namespace, or, when a pid is specified, migrate the net
+namespace to the one attached to the specified pid
.SH NOTES
The unshare command drops potential privileges before executing the
target program. This allows to setuid unshare.
+.P
+Support for migrating processes between mount and pid namespace is available in
+kernels 3.8 and later
.SH SEE ALSO
.BR unshare (2),
+.BR setns (2),
.BR clone (2)
.SH BUGS
None known so far.
-.SH AUTHOR
+.SH AUTHORS
Mikhail Gusarov <dottedmag@dottedmag.net>
+Neil Horman <nhorman@tuxdriver.com>
.SH AVAILABILITY
The unshare command is part of the util-linux package and is available from
ftp://ftp.kernel.org/pub/linux/utils/util-linux/.
diff --git a/sys-utils/unshare.c b/sys-utils/unshare.c
index 9de997bdc..64ea3766f 100644
--- a/sys-utils/unshare.c
+++ b/sys-utils/unshare.c
@@ -24,10 +24,12 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
+#include <getopt.h>
#include "nls.h"
#include "c.h"
#include "closestream.h"
+#include "strutils.h"
#ifndef CLONE_NEWSNS
# define CLONE_NEWNS 0x00020000
@@ -60,10 +62,10 @@ static void usage(int status)
_(" %s [options] <program> [args...]\n"), program_invocation_short_name);
fputs(USAGE_OPTIONS, out);
- fputs(_(" -m, --mount unshare mounts namespace\n"
- " -u, --uts unshare UTS namespace (hostname etc)\n"
- " -i, --ipc unshare System V IPC namespace\n"
- " -n, --net unshare network namespace\n"), out);
+ fputs(_(" -m, --mount [=<pid>] unshare or migrate mounts namespace\n"
+ " -u, --uts [=<pid>] unshare or migrate UTS namespace (hostname etc)\n"
+ " -i, --ipc [=<pid>] unshare or migrate System V IPC namespace\n"
+ " -n, --net [=<pid>] unshare or migrate network namespace\n"), out);
fputs(USAGE_SEPARATOR, out);
fputs(USAGE_HELP, out);
@@ -76,17 +78,18 @@ static void usage(int status)
int main(int argc, char *argv[])
{
static const struct option longopts[] = {
- { "help", no_argument, 0, 'h' },
+ { "help", no_argument, 0, 'h' },
{ "version", no_argument, 0, 'V'},
- { "mount", no_argument, 0, 'm' },
- { "uts", no_argument, 0, 'u' },
- { "ipc", no_argument, 0, 'i' },
- { "net", no_argument, 0, 'n' },
+ { "mount", optional_argument, 0, 'm' },
+ { "uts", optional_argument, 0, 'u' },
+ { "ipc", optional_argument, 0, 'i' },
+ { "net", optional_argument, 0, 'n' },
{ NULL, 0, 0, 0 }
};
+ int namespaces[128]; /* /proc/#/ns/<name> file descriptors */
+ size_t i, nscount = 0; /* number of used namespaces[] */
int unshare_flags = 0;
-
int c;
setlocale(LC_MESSAGES, "");
@@ -94,7 +97,13 @@ int main(int argc, char *argv[])
textdomain(PACKAGE);
atexit(close_stdout);
- while((c = getopt_long(argc, argv, "hVmuin", longopts, NULL)) != -1) {
+ memset(namespaces, 0, sizeof(namespaces));
+
+ while((c = getopt_long(argc, argv,
+ "hVm::u::i::n::", longopts, NULL)) != -1) {
+
+ const char *ns = NULL;
+
switch(c) {
case 'h':
usage(EXIT_SUCCESS);
@@ -102,26 +111,58 @@ int main(int argc, char *argv[])
printf(UTIL_LINUX_VERSION);
return EXIT_SUCCESS;
case 'm':
- unshare_flags |= CLONE_NEWNS;
+ ns = "mnt";
+ if (!optarg)
+ unshare_flags |= CLONE_NEWNS;
break;
case 'u':
- unshare_flags |= CLONE_NEWUTS;
+ ns = "uts";
+ if (!optarg)
+ unshare_flags |= CLONE_NEWUTS;
break;
case 'i':
- unshare_flags |= CLONE_NEWIPC;
+ ns = "ipc";
+ if (!optarg)
+ unshare_flags |= CLONE_NEWIPC;
break;
case 'n':
- unshare_flags |= CLONE_NEWNET;
+ ns = "net";
+ if (!optarg)
+ unshare_flags |= CLONE_NEWNET;
break;
default:
usage(EXIT_FAILURE);
}
+
+ if (ns && optarg) {
+ pid_t pid;
+ char path[512];
+
+ if (nscount >= ARRAY_SIZE(namespaces))
+ err(EXIT_FAILURE, _("too many new namespaces specified"));
+
+ if (*optarg == '=')
+ optarg++;
+
+ pid = strtoul_or_err(optarg, _("failed to parse pid argument"));
+
+ sprintf(path, "/proc/%lu/ns/%s", (unsigned long) pid, ns);
+ namespaces[nscount] = open(path, O_RDONLY | O_CLOEXEC);
+ if (namespaces[nscount] < 0)
+ err(EXIT_FAILURE, _("cannot open %s"), path);
+ nscount++;
+ }
}
- if(optind >= argc)
+ if (optind >= argc)
usage(EXIT_FAILURE);
- if(-1 == unshare(unshare_flags))
+ for (i = 0; i < nscount; i++) {
+ if (setns(namespaces[i], 0) != 0)
+ err(EXIT_FAILURE, _("setns failed"));
+ }
+
+ if (unshare_flags && unshare(unshare_flags) != 0)
err(EXIT_FAILURE, _("unshare failed"));
/* drop potential root euid/egid if we had been setuid'd */