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