Currently these are supported in #for-next.
Signed-off-by: Serge Hallyn <serge.hallyn@ubuntu.com>
# ifndef CLONE_NEWNS
# define CLONE_NEWNS 0x00020000
# endif
+# ifndef CLONE_NEWCGROUP
+# define CLONE_NEWCGROUP 0x02000000
+# endif
# ifndef CLONE_NEWUTS
# define CLONE_NEWUTS 0x04000000
# endif
.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).
/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
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.
* 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 }
};
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);
{ "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' },
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':
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);
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)
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.
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 }
};
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);
{ "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 },
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;
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";