3df8c3
diff -up util-linux-2.23.2/sys-utils/Makemodule.am.kzak util-linux-2.23.2/sys-utils/Makemodule.am
3df8c3
--- util-linux-2.23.2/sys-utils/Makemodule.am.kzak	2014-09-25 14:16:33.526384729 +0200
3df8c3
+++ util-linux-2.23.2/sys-utils/Makemodule.am	2014-09-25 14:15:34.861825005 +0200
3df8c3
@@ -290,6 +290,7 @@ usrbin_exec_PROGRAMS += unshare
3df8c3
 dist_man_MANS += sys-utils/unshare.1
3df8c3
 unshare_SOURCES = sys-utils/unshare.c
3df8c3
 unshare_LDADD = $(LDADD) libcommon.la
3df8c3
+unshare_CFLAGS = $(AM_CFLAGS) -I$(ul_libmount_incdir)
3df8c3
 endif
3df8c3
 
3df8c3
 if BUILD_NSENTER
3df8c3
diff -up util-linux-2.23.2/sys-utils/unshare.1.kzak util-linux-2.23.2/sys-utils/unshare.1
3df8c3
--- util-linux-2.23.2/sys-utils/unshare.1.kzak	2014-09-25 14:14:30.194208005 +0200
3df8c3
+++ util-linux-2.23.2/sys-utils/unshare.1	2014-09-25 14:15:17.617660476 +0200
3df8c3
@@ -1,63 +1,82 @@
3df8c3
 .\" Process this file with
3df8c3
 .\" groff -man -Tascii lscpu.1
3df8c3
 .\"
3df8c3
-.TH UNSHARE 1 "January 2013" "util-linux" "User Commands"
3df8c3
+.TH UNSHARE 1 "July 2013" "util-linux" "User Commands"
3df8c3
 .SH NAME
3df8c3
 unshare \- run program with some namespaces unshared from parent
3df8c3
 .SH SYNOPSIS
3df8c3
 .B unshare
3df8c3
 .RI [ options ]
3df8c3
-program
3df8c3
+.I program
3df8c3
 .RI [ arguments ]
3df8c3
 .SH DESCRIPTION
3df8c3
-Unshares specified namespaces from parent process and then executes specified
3df8c3
-program. Unshareable namespaces are:
3df8c3
+Unshares the indicated namespaces from the parent process and then executes
3df8c3
+the specified program.  The namespaces to be unshared are indicated via
3df8c3
+options.  Unshareable namespaces are:
3df8c3
 .TP
3df8c3
 .BR "mount namespace"
3df8c3
-mounting and unmounting filesystems will not affect rest of the system
3df8c3
+Mounting and unmounting filesystems will not affect the rest of the system
3df8c3
 (\fBCLONE_NEWNS\fP flag), except for filesystems which are explicitly marked as
3df8c3
-shared (by mount --make-shared). See /proc/self/mountinfo for the shared flags.
3df8c3
+shared (with \fBmount --make-shared\fP; see \fI/proc/self/mountinfo\fP for the
3df8c3
+\fBshared\fP flags).
3df8c3
+
3df8c3
+It's recommended to use \fBmount --make-rprivate\fP or \fBmount --make-rslave\fP
3df8c3
+after \fBunshare --mount\fP to make sure that mountpoints in the new namespace
3df8c3
+are really unshared from parental namespace.
3df8c3
 .TP
3df8c3
 .BR "UTS namespace"
3df8c3
-setting hostname, domainname will not affect rest of the system
3df8c3
-(\fBCLONE_NEWUTS\fP flag).
3df8c3
+Setting hostname or domainname will not affect the rest of the system.
3df8c3
+(\fBCLONE_NEWUTS\fP flag)
3df8c3
 .TP
3df8c3
 .BR "IPC namespace"
3df8c3
-process will have independent namespace for System V message queues, semaphore
3df8c3
-sets and shared memory segments (\fBCLONE_NEWIPC\fP flag).
3df8c3
+The process will have an independent namespace for System V message queues,
3df8c3
+semaphore sets and shared memory segments.  (\fBCLONE_NEWIPC\fP flag)
3df8c3
 .TP
3df8c3
 .BR "network namespace"
3df8c3
-process will have independent IPv4 and IPv6 stacks, IP routing tables, firewall
3df8c3
-rules, the \fI/proc/net\fP and \fI/sys/class/net\fP directory trees, sockets
3df8c3
-etc. (\fBCLONE_NEWNET\fP flag).
3df8c3
+The process will have independent IPv4 and IPv6 stacks, IP routing tables,
3df8c3
+firewall rules, the \fI/proc/net\fP and \fI/sys/class/net\fP directory trees,
3df8c3
+sockets, etc.  (\fBCLONE_NEWNET\fP flag)
3df8c3
 .TP
3df8c3
 .BR "pid namespace"
3df8c3
-children will have a distinct set of pid to process mappings than their parent.
3df8c3
-(\fBCLONE_NEWPID\fP flag).
3df8c3
+Children will have a distinct set of PID to process mappings from their parent.
3df8c3
+(\fBCLONE_NEWPID\fP flag)
3df8c3
 .PP
3df8c3
-See the \fBclone\fR(2) for exact semantics of the flags.
3df8c3
+See \fBclone\fR(2) for the exact semantics of the flags.
3df8c3
 .SH OPTIONS
3df8c3
 .TP
3df8c3
 .BR \-h , " \-\-help"
3df8c3
-Print a help message,
3df8c3
-.TP
3df8c3
-.BR \-m , " \-\-mount"
3df8c3
-Unshare the mount namespace,
3df8c3
-.TP
3df8c3
-.BR \-u , " \-\-uts"
3df8c3
-Unshare the UTS namespace,
3df8c3
+Display help text and exit.
3df8c3
 .TP
3df8c3
 .BR \-i , " \-\-ipc"
3df8c3
-Unshare the IPC namespace,
3df8c3
+Unshare the IPC namespace.
3df8c3
+.TP
3df8c3
+.BR \-m , " \-\-mount"
3df8c3
+Unshare the mount namespace.
3df8c3
 .TP
3df8c3
 .BR \-n , " \-\-net"
3df8c3
 Unshare the network namespace.
3df8c3
 .TP
3df8c3
 .BR \-p , " \-\-pid"
3df8c3
 Unshare the pid namespace.
3df8c3
+See also the \fB--fork\fP and \fB--mount-proc\fP options.
3df8c3
+.TP
3df8c3
+.BR \-u , " \-\-uts"
3df8c3
+Unshare the UTS namespace.
3df8c3
+.TP
3df8c3
+.BR \-f , " \-\-fork"
3df8c3
+Fork the specified \fIprogram\fR as a child process of \fBunshare\fR rather than
3df8c3
+running it directly.  This is useful when creating a new pid namespace.
3df8c3
+.TP
3df8c3
+.BR \-\-mount-proc "[=\fImountpoint\fP]"
3df8c3
+Just before running the program, mount the proc filesystem at the \fImountpoint\fP
3df8c3
+(default is /proc).  This is useful when creating a new pid namespace.  It also
3df8c3
+implies creating a new mount namespace since the /proc mount would otherwise
3df8c3
+mess up existing programs on the system. The new proc filesystem is explicitly
3df8c3
+mounted as private (by MS_PRIVATE|MS_REC).
3df8c3
 .SH SEE ALSO
3df8c3
 .BR unshare (2),
3df8c3
-.BR clone (2)
3df8c3
+.BR clone (2),
3df8c3
+.BR mount (8)
3df8c3
 .SH BUGS
3df8c3
 None known so far.
3df8c3
 .SH AUTHOR
3df8c3
diff -up util-linux-2.23.2/sys-utils/unshare.c.kzak util-linux-2.23.2/sys-utils/unshare.c
3df8c3
--- util-linux-2.23.2/sys-utils/unshare.c.kzak	2014-09-25 14:14:30.194208005 +0200
3df8c3
+++ util-linux-2.23.2/sys-utils/unshare.c	2014-09-25 14:15:34.861825005 +0200
3df8c3
@@ -24,12 +24,19 @@
3df8c3
 #include <stdio.h>
3df8c3
 #include <stdlib.h>
3df8c3
 #include <unistd.h>
3df8c3
+#include <sys/wait.h>
3df8c3
+#include <sys/mount.h>
3df8c3
+
3df8c3
+/* we only need some defines missing in sys/mount.h, no libmount linkage */
3df8c3
+#include <libmount.h>
3df8c3
 
3df8c3
 #include "nls.h"
3df8c3
 #include "c.h"
3df8c3
-#include "closestream.h"
3df8c3
 #include "namespace.h"
3df8c3
 #include "exec_shell.h"
3df8c3
+#include "xalloc.h"
3df8c3
+#include "pathnames.h"
3df8c3
+
3df8c3
 
3df8c3
 static void usage(int status)
3df8c3
 {
3df8c3
@@ -40,11 +47,13 @@ static void usage(int status)
3df8c3
 	      _(" %s [options] <program> [args...]\n"),	program_invocation_short_name);
3df8c3
 
3df8c3
 	fputs(USAGE_OPTIONS, out);
3df8c3
-	fputs(_(" -m, --mount       unshare mounts namespace\n"), out);
3df8c3
-	fputs(_(" -u, --uts         unshare UTS namespace (hostname etc)\n"), out);
3df8c3
-	fputs(_(" -i, --ipc         unshare System V IPC namespace\n"), out);
3df8c3
-	fputs(_(" -n, --net         unshare network namespace\n"), out);
3df8c3
-	fputs(_(" -p, --pid         unshare pid namespace\n"), out);
3df8c3
+	fputs(_(" -m, --mount               unshare mounts namespace\n"), out);
3df8c3
+	fputs(_(" -u, --uts                 unshare UTS namespace (hostname etc)\n"), out);
3df8c3
+	fputs(_(" -i, --ipc                 unshare System V IPC namespace\n"), out);
3df8c3
+	fputs(_(" -n, --net                 unshare network namespace\n"), out);
3df8c3
+	fputs(_(" -p, --pid                 unshare pid namespace\n"), out);
3df8c3
+	fputs(_(" -f, --fork                fork before launching <program>\n"), out);
3df8c3
+	fputs(_("     --mount-proc[=<dir>]  mount proc filesystem first (implies --mount)\n"), out);
3df8c3
 
3df8c3
 	fputs(USAGE_SEPARATOR, out);
3df8c3
 	fputs(USAGE_HELP, out);
3df8c3
@@ -56,6 +65,9 @@ static void usage(int status)
3df8c3
 
3df8c3
 int main(int argc, char *argv[])
3df8c3
 {
3df8c3
+	enum {
3df8c3
+		OPT_MOUNTPROC = CHAR_MAX + 1
3df8c3
+	};
3df8c3
 	static const struct option longopts[] = {
3df8c3
 		{ "help", no_argument, 0, 'h' },
3df8c3
 		{ "version", no_argument, 0, 'V'},
3df8c3
@@ -64,20 +76,24 @@ int main(int argc, char *argv[])
3df8c3
 		{ "ipc", no_argument, 0, 'i' },
3df8c3
 		{ "net", no_argument, 0, 'n' },
3df8c3
 		{ "pid", no_argument, 0, 'p' },
3df8c3
+		{ "fork", no_argument, 0, 'f' },
3df8c3
+		{ "mount-proc", optional_argument, 0, OPT_MOUNTPROC },
3df8c3
 		{ NULL, 0, 0, 0 }
3df8c3
 	};
3df8c3
 
3df8c3
 	int unshare_flags = 0;
3df8c3
+	int c, forkit = 0;
3df8c3
+	const char *procmnt = NULL;
3df8c3
 
3df8c3
-	int c;
3df8c3
-
3df8c3
-	setlocale(LC_MESSAGES, "");
3df8c3
+	setlocale(LC_ALL, "");
3df8c3
 	bindtextdomain(PACKAGE, LOCALEDIR);
3df8c3
 	textdomain(PACKAGE);
3df8c3
-	atexit(close_stdout);
3df8c3
 
3df8c3
-	while ((c = getopt_long(argc, argv, "hVmuinp", longopts, NULL)) != -1) {
3df8c3
+	while ((c = getopt_long(argc, argv, "+fhVmuinp", longopts, NULL)) != -1) {
3df8c3
 		switch (c) {
3df8c3
+		case 'f':
3df8c3
+			forkit = 1;
3df8c3
+			break;
3df8c3
 		case 'h':
3df8c3
 			usage(EXIT_SUCCESS);
3df8c3
 		case 'V':
3df8c3
@@ -98,6 +114,10 @@ int main(int argc, char *argv[])
3df8c3
 		case 'p':
3df8c3
 			unshare_flags |= CLONE_NEWPID;
3df8c3
 			break;
3df8c3
+		case OPT_MOUNTPROC:
3df8c3
+			unshare_flags |= CLONE_NEWNS;
3df8c3
+			procmnt = optarg ? optarg : "/proc";
3df8c3
+			break;
3df8c3
 		default:
3df8c3
 			usage(EXIT_FAILURE);
3df8c3
 		}
3df8c3
@@ -106,6 +126,31 @@ int main(int argc, char *argv[])
3df8c3
 	if (-1 == unshare(unshare_flags))
3df8c3
 		err(EXIT_FAILURE, _("unshare failed"));
3df8c3
 
3df8c3
+	if (forkit) {
3df8c3
+		int status;
3df8c3
+		pid_t pid = fork();
3df8c3
+
3df8c3
+		switch(pid) {
3df8c3
+		case -1:
3df8c3
+			err(EXIT_FAILURE, _("fork failed"));
3df8c3
+		case 0:	/* child */
3df8c3
+			break;
3df8c3
+		default: /* parent */
3df8c3
+			if (waitpid(pid, &status, 0) == -1)
3df8c3
+				err(EXIT_FAILURE, _("waitpid failed"));
3df8c3
+			if (WIFEXITED(status))
3df8c3
+				return WEXITSTATUS(status);
3df8c3
+			else if (WIFSIGNALED(status))
3df8c3
+				kill(getpid(), WTERMSIG(status));
3df8c3
+			err(EXIT_FAILURE, _("child exit failed"));
3df8c3
+		}
3df8c3
+	}
3df8c3
+
3df8c3
+	if (procmnt &&
3df8c3
+	    (mount("none", procmnt, NULL, MS_PRIVATE|MS_REC, NULL) != 0 ||
3df8c3
+	     mount("proc", procmnt, "proc", MS_NOSUID|MS_NOEXEC|MS_NODEV, NULL) != 0))
3df8c3
+			err(EXIT_FAILURE, _("mount %s failed"), procmnt);
3df8c3
+
3df8c3
 	if (optind < argc) {
3df8c3
 		execvp(argv[optind], argv + optind);
3df8c3
 		err(EXIT_FAILURE, _("failed to execute %s"), argv[optind]);