[PATCH v3] sys-tools: Enhance unshare command to support the switching of namespaces

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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

Signed-off-by: Neil Horman <nhorman@xxxxxxxxxxxxx>
CC: Karel Zak <kzak@xxxxxxxxxx>
---
 sys-utils/unshare.1 | 34 +++++++++++++++---------
 sys-utils/unshare.c | 74 ++++++++++++++++++++++++++++++++++++++++++-----------
 2 files changed, 81 insertions(+), 27 deletions(-)

diff --git a/sys-utils/unshare.1 b/sys-utils/unshare.1
index 1325e34..e0393f7 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
@@ -32,32 +32,42 @@ rules, the \fI/proc/net\fP and \fI/sys/class/net\fP directory trees, sockets
 etc. (\fBCLONE_NEWNET\fP flag).
 .TP
 See the \fBclone\fR(2) for exact semantics of the flags.
+.TP
 .SH OPTIONS
 .TP
 .BR \-h , " \-\-help"
 Print a help message,
 .TP
-.BR \-m , " \-\-mount"
-Unshare the mount namespace,
+.BR \-m\ [pid] , " \-\-mount[=pid]"
+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\ [pid] , " \-\-uts[=pid]"
+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\ [pid] , " \-\-ipc[=pid]"
+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\ [pid] , " \-\-net[=pid]"
+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 mnt 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@xxxxxxxxxxxxx>
+Neil Horman <nhorman@xxxxxxxxxxxxx>
 .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 9de997b..e67986a 100644
--- a/sys-utils/unshare.c
+++ b/sys-utils/unshare.c
@@ -24,6 +24,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
+#include <getopt.h>
 
 #include "nls.h"
 #include "c.h"
@@ -42,6 +43,9 @@
 # define CLONE_NEWNET 0x40000000
 #endif
 
+#define NUM_ENTRIES 128
+static int ns_pids[128];
+
 #ifndef HAVE_UNSHARE
 # include <sys/syscall.h>
 
@@ -60,10 +64,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       unshare|migrate mounts namespace\n"
+		" -u, --uts         unshare|migrate UTS namespace (hostname etc)\n"
+		" -i, --ipc         unshare|migrate System V IPC namespace\n"
+		" -n, --net         unshare|migrate network namespace\n"), out);
 
 	fputs(USAGE_SEPARATOR, out);
 	fputs(USAGE_HELP, out);
@@ -73,28 +77,42 @@ static void usage(int status)
 	exit(status);
 }
 
+static void close_files(void)
+{
+	int i;
+	for (i=0; ns_pids[i] > 0; i++)
+		close(ns_pids[i]);
+	close_stdout();
+}
+
 int main(int argc, char *argv[])
 {
 	static const struct option longopts[] = {
 		{ "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 unshare_flags = 0;
-
+	int nscount = 0;
 	int c;
+	char *ns;
+	unsigned long pid;
+	char path[512];
 
+	memset(ns_pids, 0, sizeof(int)*NUM_ENTRIES);
 	setlocale(LC_MESSAGES, "");
 	bindtextdomain(PACKAGE, LOCALEDIR);
 	textdomain(PACKAGE);
-	atexit(close_stdout);
+	atexit(close_files);
+
+	while((c = getopt_long(argc, argv, "hVm:u:i:n:", longopts, NULL)) != -1) {
+		ns = NULL;
 
-	while((c = getopt_long(argc, argv, "hVmuin", longopts, NULL)) != -1) {
 		switch(c) {
 		case 'h':
 			usage(EXIT_SUCCESS);
@@ -102,25 +120,51 @@ 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 (optarg && ns) {
+				if (nscount >= NUM_ENTRIES)
+					err(EXIT_FAILURE, _("Too many new namespaces specified"));
+				pid = strtoul(optarg, NULL, 10);
+				if (pid == ULONG_MAX)
+					err(EXIT_FAILURE, _("%s pid improperly specified"), ns);
+				sprintf(path, "/proc/%d/ns/%s", (int)pid, ns); 
+				ns_pids[nscount] = open(path, O_RDONLY);
+				if (ns_pids[nscount] < 0)
+					err(EXIT_FAILURE, _("Can not migrate %s: Can't open %s"), ns, path);
+				nscount++;
+		}
+		
 	}
 
 	if(optind >= argc)
 		usage(EXIT_FAILURE);
 
+	for (nscount = 0; ns_pids[nscount] > 0; nscount++)
+		if (-1 == setns(ns_pids[nscount], 0))
+			err(EXIT_FAILURE, _("setns failed"));
+	
 	if(-1 == unshare(unshare_flags))
 		err(EXIT_FAILURE, _("unshare failed"));
 
-- 
1.7.11.7

--
To unsubscribe from this list: send the line "unsubscribe util-linux" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Netdev]     [Ethernet Bridging]     [Linux Wireless]     [Kernel Newbies]     [Security]     [Linux for Hams]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux Admin]     [Samba]

  Powered by Linux