Implement support for cgroup namespaces

Currently these are supported in #for-next.

Signed-off-by: Serge Hallyn <serge.hallyn@ubuntu.com>
This commit is contained in:
Serge Hallyn 2016-03-02 17:53:42 -08:00
parent 7154cc8926
commit f9e7b66dbd
5 changed files with 63 additions and 20 deletions

View File

@ -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

View File

@ -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.

View File

@ -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[=<file>] enter System V IPC namespace\n"), out);
fputs(_(" -n, --net[=<file>] enter network namespace\n"), out);
fputs(_(" -p, --pid[=<file>] enter pid namespace\n"), out);
fputs(_(" -C, --cgroup[=<file>] enter cgroup namespace\n"), out);
fputs(_(" -U, --user[=<file>] enter user namespace\n"), out);
fputs(_(" -S, --setuid <uid> set uid in entered namespace\n"), out);
fputs(_(" -G, --setgid <gid> 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);

View File

@ -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.

View File

@ -53,12 +53,13 @@ static struct namespace_file {
const char *name; /* ns/<type> */
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[=<file>] unshare network namespace\n"), out);
fputs(_(" -p, --pid[=<file>] unshare pid namespace\n"), out);
fputs(_(" -U, --user[=<file>] unshare user namespace\n"), out);
fputs(_(" -C, --cgroup[=<file>] unshare cgroup namespace\n"), out);
fputs(_(" -f, --fork fork before launching <program>\n"), out);
fputs(_(" --mount-proc[=<dir>] 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";