From f9e7b66dbded19d798b883be68b0613749d7b8bb Mon Sep 17 00:00:00 2001 From: Serge Hallyn Date: Wed, 2 Mar 2016 17:53:42 -0800 Subject: Implement support for cgroup namespaces Currently these are supported in #for-next. Signed-off-by: Serge Hallyn --- include/namespace.h | 3 +++ sys-utils/nsenter.1 | 14 ++++++++++++++ sys-utils/nsenter.c | 23 ++++++++++++++++------- sys-utils/unshare.1 | 9 +++++++++ sys-utils/unshare.c | 34 +++++++++++++++++++++------------- 5 files changed, 63 insertions(+), 20 deletions(-) diff --git a/include/namespace.h b/include/namespace.h index ea231cacb..9dbe88aa0 100644 --- a/include/namespace.h +++ b/include/namespace.h @@ -7,6 +7,9 @@ # ifndef CLONE_NEWNS # define CLONE_NEWNS 0x00020000 # endif +# ifndef CLONE_NEWCGROUP +# define CLONE_NEWCGROUP 0x02000000 +# endif # ifndef CLONE_NEWUTS # define CLONE_NEWUTS 0x04000000 # endif diff --git a/sys-utils/nsenter.1 b/sys-utils/nsenter.1 index 79fc2e5c6..ea5992e73 100644 --- a/sys-utils/nsenter.1 +++ b/sys-utils/nsenter.1 @@ -54,6 +54,12 @@ The process will have a distinct set of UIDs, GIDs and capabilities. .RB ( CLONE_\:NEWUSER flag) .TP +.B cgroup namespace +The process will have a virtualized view of \fI/proc\:/self\:/cgroup\fP, and new +cgroup mounts will be rooted at the namespace cgroup root. +.RB ( CLONE_\:NEWCGROUP +flag) +.TP See \fBclone\fP(2) for the exact semantics of the flags. .TP If \fIprogram\fP is not given, then ``${SHELL}'' is run (default: /bin\:/sh). @@ -87,6 +93,9 @@ the PID namespace /proc/\fIpid\fR/ns/user the user namespace .TP +/proc/\fIpid\fR/ns/cgroup +the cgroup namespace +.TP /proc/\fIpid\fR/root the root directory .TP @@ -125,6 +134,11 @@ Enter the user namespace. If no file is specified, enter the user namespace of the target process. If file is specified, enter the user namespace specified by file. See also the \fB\-\-setuid\fR and \fB\-\-setgid\fR options. .TP +\fB\-C\fR, \fB\-\-cgroup\fR[=\fIfile\fR] +Enter the cgroup namespace. If no file is specified, enter the cgroup namespace of +the target process. If file is specified, enter the cgroup namespace specified by +file. +.TP \fB\-G\fR, \fB\-\-setgid\fR \fIgid\fR Set the group ID which will be used in the entered namespace and drop supplementary groups. diff --git a/sys-utils/nsenter.c b/sys-utils/nsenter.c index 371572580..d8690db36 100644 --- a/sys-utils/nsenter.c +++ b/sys-utils/nsenter.c @@ -52,12 +52,13 @@ static struct namespace_file { * first. This gives an unprivileged user the potential to * enter the other namespaces. */ - { .nstype = CLONE_NEWUSER, .name = "ns/user", .fd = -1 }, - { .nstype = CLONE_NEWIPC, .name = "ns/ipc", .fd = -1 }, - { .nstype = CLONE_NEWUTS, .name = "ns/uts", .fd = -1 }, - { .nstype = CLONE_NEWNET, .name = "ns/net", .fd = -1 }, - { .nstype = CLONE_NEWPID, .name = "ns/pid", .fd = -1 }, - { .nstype = CLONE_NEWNS, .name = "ns/mnt", .fd = -1 }, + { .nstype = CLONE_NEWUSER, .name = "ns/user", .fd = -1 }, + { .nstype = CLONE_NEWCGROUP,.name = "ns/cgroup", .fd = -1 }, + { .nstype = CLONE_NEWIPC, .name = "ns/ipc", .fd = -1 }, + { .nstype = CLONE_NEWUTS, .name = "ns/uts", .fd = -1 }, + { .nstype = CLONE_NEWNET, .name = "ns/net", .fd = -1 }, + { .nstype = CLONE_NEWPID, .name = "ns/pid", .fd = -1 }, + { .nstype = CLONE_NEWNS, .name = "ns/mnt", .fd = -1 }, { .nstype = 0, .name = NULL, .fd = -1 } }; @@ -79,6 +80,7 @@ static void usage(int status) fputs(_(" -i, --ipc[=] enter System V IPC namespace\n"), out); fputs(_(" -n, --net[=] enter network namespace\n"), out); fputs(_(" -p, --pid[=] enter pid namespace\n"), out); + fputs(_(" -C, --cgroup[=] enter cgroup namespace\n"), out); fputs(_(" -U, --user[=] enter user namespace\n"), out); fputs(_(" -S, --setuid set uid in entered namespace\n"), out); fputs(_(" -G, --setgid set gid in entered namespace\n"), out); @@ -186,6 +188,7 @@ int main(int argc, char *argv[]) { "net", optional_argument, NULL, 'n' }, { "pid", optional_argument, NULL, 'p' }, { "user", optional_argument, NULL, 'U' }, + { "cgroup", optional_argument, NULL, 'C' }, { "setuid", required_argument, NULL, 'S' }, { "setgid", required_argument, NULL, 'G' }, { "root", optional_argument, NULL, 'r' }, @@ -214,7 +217,7 @@ int main(int argc, char *argv[]) atexit(close_stdout); while ((c = - getopt_long(argc, argv, "+hVt:m::u::i::n::p::U::S:G:r::w::FZ", + getopt_long(argc, argv, "+hVt:m::u::i::n::p::C::U::S:G:r::w::FZ", longopts, NULL)) != -1) { switch (c) { case 'h': @@ -256,6 +259,12 @@ int main(int argc, char *argv[]) else namespaces |= CLONE_NEWPID; break; + case 'C': + if (optarg) + open_namespace_fd(CLONE_NEWCGROUP, optarg); + else + namespaces |= CLONE_NEWCGROUP; + break; case 'U': if (optarg) open_namespace_fd(CLONE_NEWUSER, optarg); diff --git a/sys-utils/unshare.1 b/sys-utils/unshare.1 index 264f13969..973bc048c 100644 --- a/sys-utils/unshare.1 +++ b/sys-utils/unshare.1 @@ -49,6 +49,11 @@ sockets, etc. (\fBCLONE_NEWNET\fP flag) Children will have a distinct set of PID to process mappings from their parent. (\fBCLONE_NEWPID\fP flag) .TP +.BR "cgroup namespace" +The process will have a virtualized view of \fI/proc\:/self\:/cgroup\fP, and new +cgroup mounts will be rooted at the namespace cgroup root. +(\fBCLONE_NEWCGROUP\fP flag) +.TP .BR "user namespace" The process will have a distinct set of UIDs, GIDs and capabilities. (\fBCLONE_NEWUSER\fP flag) @@ -82,6 +87,10 @@ by bind mount. Unshare the user namespace. If \fIfile\fP is specified then persistent namespace is created by bind mount. .TP +.BR \-C , " \-\-cgroup"[=\fIfile\fP] +Unshare the cgroup namespace. If \fIfile\fP is specified then persistent namespace is created +by bind mount. +.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. diff --git a/sys-utils/unshare.c b/sys-utils/unshare.c index 988632062..234c7501f 100644 --- a/sys-utils/unshare.c +++ b/sys-utils/unshare.c @@ -53,12 +53,13 @@ static struct namespace_file { const char *name; /* ns/ */ const char *target; /* user specified target for bind mount */ } namespace_files[] = { - { .type = CLONE_NEWUSER, .name = "ns/user" }, - { .type = CLONE_NEWIPC, .name = "ns/ipc" }, - { .type = CLONE_NEWUTS, .name = "ns/uts" }, - { .type = CLONE_NEWNET, .name = "ns/net" }, - { .type = CLONE_NEWPID, .name = "ns/pid" }, - { .type = CLONE_NEWNS, .name = "ns/mnt" }, + { .type = CLONE_NEWUSER, .name = "ns/user" }, + { .type = CLONE_NEWCGROUP,.name = "ns/cgroup" }, + { .type = CLONE_NEWIPC, .name = "ns/ipc" }, + { .type = CLONE_NEWUTS, .name = "ns/uts" }, + { .type = CLONE_NEWNET, .name = "ns/net" }, + { .type = CLONE_NEWPID, .name = "ns/pid" }, + { .type = CLONE_NEWNS, .name = "ns/mnt" }, { .name = NULL } }; @@ -255,6 +256,7 @@ static void usage(int status) fputs(_(" -n, --net[=] unshare network namespace\n"), out); fputs(_(" -p, --pid[=] unshare pid namespace\n"), out); fputs(_(" -U, --user[=] unshare user namespace\n"), out); + fputs(_(" -C, --cgroup[=] unshare cgroup namespace\n"), out); fputs(_(" -f, --fork fork before launching \n"), out); fputs(_(" --mount-proc[=] mount proc filesystem first (implies --mount)\n"), out); fputs(_(" -r, --map-root-user map current user to root (implies --user)\n"), out); @@ -281,12 +283,13 @@ int main(int argc, char *argv[]) { "help", no_argument, 0, 'h' }, { "version", no_argument, 0, 'V'}, - { "mount", optional_argument, 0, 'm' }, - { "uts", optional_argument, 0, 'u' }, - { "ipc", optional_argument, 0, 'i' }, - { "net", optional_argument, 0, 'n' }, - { "pid", optional_argument, 0, 'p' }, - { "user", optional_argument, 0, 'U' }, + { "mount", optional_argument, 0, 'm' }, + { "uts", optional_argument, 0, 'u' }, + { "ipc", optional_argument, 0, 'i' }, + { "net", optional_argument, 0, 'n' }, + { "pid", optional_argument, 0, 'p' }, + { "user", optional_argument, 0, 'U' }, + { "cgroup", optional_argument, 0, 'C' }, { "fork", no_argument, 0, 'f' }, { "mount-proc", optional_argument, 0, OPT_MOUNTPROC }, @@ -312,7 +315,7 @@ int main(int argc, char *argv[]) textdomain(PACKAGE); atexit(close_stdout); - while ((c = getopt_long(argc, argv, "+fhVmuinpUr", longopts, NULL)) != -1) { + while ((c = getopt_long(argc, argv, "+fhVmuinpCUr", longopts, NULL)) != -1) { switch (c) { case 'f': forkit = 1; @@ -352,6 +355,11 @@ int main(int argc, char *argv[]) if (optarg) set_ns_target(CLONE_NEWUSER, optarg); break; + case 'C': + unshare_flags |= CLONE_NEWCGROUP; + if (optarg) + set_ns_target(CLONE_NEWCGROUP, optarg); + break; case OPT_MOUNTPROC: unshare_flags |= CLONE_NEWNS; procmnt = optarg ? optarg : "/proc"; -- cgit v1.2.3-55-g7522