unshare: add --mount-proc for pid namespaces

Based on patch from Mike Frysinger <vapier@gentoo.org>.

Mike Frysinger wrote:
 When it comes to pid namespaces, it's also useful for /proc to reflect
 the current namespace.  Again, this is easy to pull off, but annoying
 to force everyone to do it themselves.  So let's add a --mount-proc to
 do the magic for us.  The downside is that this also implies creating
 a mount namespace as mounting the new pid namespace /proc over top the
 system one will quickly break all other processes on the system.

Signed-off-by: Karel Zak <kzak@redhat.com>
Acked-by: Mike Frysinger <vapier@gentoo.or>
This commit is contained in:
Karel Zak 2013-07-03 12:28:16 +02:00
parent 5088ec338f
commit 6728ca101e
2 changed files with 30 additions and 8 deletions

View File

@ -56,7 +56,7 @@ Unshare the mount namespace.
Unshare the network namespace. Unshare the network namespace.
.TP .TP
.BR \-p , " \-\-pid" .BR \-p , " \-\-pid"
Unshare the pid namespace. See also \fB--fork\fP option. Unshare the pid namespace. See also \fB--fork\fP and \fB--mount-proc\fP options.
.TP .TP
.BR \-u , " \-\-uts" .BR \-u , " \-\-uts"
Unshare the UTS namespace. Unshare the UTS namespace.
@ -67,6 +67,12 @@ Unshare the user namespace.
.BR \-f , " \-\-fork" .BR \-f , " \-\-fork"
Fork the specified process as a child of unshare rather than running it Fork the specified process as a child of unshare rather than running it
directly. This is useful when creating a new pid namespace. directly. This is useful when creating a new pid namespace.
.TP
.BR "\fB\-\-mount-proc\fR [=\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.
.SH SEE ALSO .SH SEE ALSO
.BR unshare (2), .BR unshare (2),
.BR clone (2) .BR clone (2)

View File

@ -25,6 +25,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h> #include <unistd.h>
#include <sys/wait.h> #include <sys/wait.h>
#include <sys/mount.h>
#include "nls.h" #include "nls.h"
#include "c.h" #include "c.h"
@ -41,13 +42,14 @@ static void usage(int status)
_(" %s [options] <program> [args...]\n"), program_invocation_short_name); _(" %s [options] <program> [args...]\n"), program_invocation_short_name);
fputs(USAGE_OPTIONS, out); fputs(USAGE_OPTIONS, out);
fputs(_(" -m, --mount unshare mounts namespace\n"), out); fputs(_(" -m, --mount unshare mounts namespace\n"), out);
fputs(_(" -u, --uts unshare UTS namespace (hostname etc)\n"), out); fputs(_(" -u, --uts unshare UTS namespace (hostname etc)\n"), out);
fputs(_(" -i, --ipc unshare System V IPC namespace\n"), out); fputs(_(" -i, --ipc unshare System V IPC namespace\n"), out);
fputs(_(" -n, --net unshare network namespace\n"), out); fputs(_(" -n, --net unshare network namespace\n"), out);
fputs(_(" -p, --pid unshare pid namespace\n"), out); fputs(_(" -p, --pid unshare pid namespace\n"), out);
fputs(_(" -U, --user unshare user namespace\n"), out); fputs(_(" -U, --user unshare user namespace\n"), out);
fputs(_(" -f, --fork fork before launching <program>\n"), out); fputs(_(" -f, --fork fork before launching <program>\n"), out);
fputs(_(" --mount-proc[=<dir>] mount proc filesystem first (implies --mount)\n"), out);
fputs(USAGE_SEPARATOR, out); fputs(USAGE_SEPARATOR, out);
fputs(USAGE_HELP, out); fputs(USAGE_HELP, out);
@ -59,6 +61,9 @@ static void usage(int status)
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
enum {
OPT_MOUNTPROC = CHAR_MAX + 1
};
static const struct option longopts[] = { static const struct option longopts[] = {
{ "help", no_argument, 0, 'h' }, { "help", no_argument, 0, 'h' },
{ "version", no_argument, 0, 'V'}, { "version", no_argument, 0, 'V'},
@ -69,11 +74,13 @@ int main(int argc, char *argv[])
{ "pid", no_argument, 0, 'p' }, { "pid", no_argument, 0, 'p' },
{ "user", no_argument, 0, 'U' }, { "user", no_argument, 0, 'U' },
{ "fork", no_argument, 0, 'f' }, { "fork", no_argument, 0, 'f' },
{ "mount-proc", optional_argument, 0, OPT_MOUNTPROC },
{ NULL, 0, 0, 0 } { NULL, 0, 0, 0 }
}; };
int unshare_flags = 0; int unshare_flags = 0;
int c, forkit = 0; int c, forkit = 0;
const char *procmnt = NULL;
setlocale(LC_MESSAGES, ""); setlocale(LC_MESSAGES, "");
bindtextdomain(PACKAGE, LOCALEDIR); bindtextdomain(PACKAGE, LOCALEDIR);
@ -108,6 +115,10 @@ int main(int argc, char *argv[])
case 'U': case 'U':
unshare_flags |= CLONE_NEWUSER; unshare_flags |= CLONE_NEWUSER;
break; break;
case OPT_MOUNTPROC:
unshare_flags |= CLONE_NEWNS;
procmnt = optarg ? optarg : "/proc";
break;
default: default:
usage(EXIT_FAILURE); usage(EXIT_FAILURE);
} }
@ -136,6 +147,11 @@ int main(int argc, char *argv[])
} }
} }
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) { if (optind < argc) {
execvp(argv[optind], argv + optind); execvp(argv[optind], argv + optind);
err(EXIT_FAILURE, _("failed to execute %s"), argv[optind]); err(EXIT_FAILURE, _("failed to execute %s"), argv[optind]);