Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1278963 > unrolled thread
| Started by | serge.hallyn@ubuntu.com |
|---|---|
| First post | 2015-11-27 22:00 +0100 |
| Last post | 2015-11-27 22:00 +0100 |
| Articles | 3 — 1 participant |
Back to article view | Back to linux.kernel
CGroup Namespaces (v5) serge.hallyn@ubuntu.com - 2015-11-27 22:00 +0100
[PATCH 6/7] cgroup: Add documentation for cgroup namespaces serge.hallyn@ubuntu.com - 2015-11-27 22:00 +0100
[PATCH 5/7] cgroup: mount cgroupns-root when inside non-init cgroupns serge.hallyn@ubuntu.com - 2015-11-27 22:00 +0100
| From | serge.hallyn@ubuntu.com |
|---|---|
| Date | 2015-11-27 22:00 +0100 |
| Subject | CGroup Namespaces (v5) |
| Message-ID | <qzyhz-7Kz-3@gated-at.bofh.it> |
Hi,
following is a revised set of the CGroup Namespace patchset which Aditya
Kali has previously sent. The code can also be found in the cgroupns.v5
branch of
https://git.kernel.org/cgit/linux/kernel/git/sergeh/linux-security.git/
To summarize the semantics:
1. CLONE_NEWCGROUP re-uses 0x02000000, which was previously CLONE_STOPPED
2. unsharing a cgroup namespace makes all your current cgroups your new
cgroup root.
3. /proc/pid/cgroup always shows cgroup paths relative to the reader's
cgroup namespce root. A task outside of your cgroup looks like
8:memory:/../../..
4. when a task mounts a cgroupfs, the cgroup which shows up as root depends
on the mounting task's cgroup namespace.
5. setns to a cgroup namespace switches your cgroup namespace but not
your cgroups.
With this, using github.com/hallyn/lxc #2015-11-09/cgns (and
github.com/hallyn/lxcfs #2015-11-10/cgns) we can start a container in a full
proper cgroup namespace, avoiding either cgmanager or lxcfs cgroup bind mounts.
This is completely backward compatible and will be completely invisible
to any existing cgroup users (except for those running inside a cgroup
namespace and looking at /proc/pid/cgroup of tasks outside their
namespace.)
Changes from V4:
1. Move the FS_USERNS_MOUNT flag to last patch
2. Rebase onto cgroup/for-4.5
3. Don't non-init user namespaces to bind new subsystems when mounting.
4. Address feedback from Tejun (thanks). Specificaly, not addressed:
. kernfs_obtain_root - walking dentry from kernfs root.
(I think that's the only piece)
5. Dropped unused get_task_cgroup fn/patch.
6. Reworked kernfs_path_from_node_locked() to try to simplify the logic.
It now finds a common ancestor, walks from the source to it, then back
up to the target.
Changes from V3:
1. Rebased onto latest cgroup changes. In particular switch to
css_set_lock and ns_common.
2. Support all hierarchies.
Changes from V2:
1. Added documentation in Documentation/cgroups/namespace.txt
2. Fixed a bug that caused crash
3. Incorporated some other suggestions from last patchset:
- removed use of threadgroup_lock() while creating new cgroupns
- use task_lock() instead of rcu_read_lock() while accessing
task->nsproxy
- optimized setns() to own cgroupns
- simplified code around sane-behavior mount option parsing
4. Restored ACKs from Serge Hallyn from v1 on few patches that have
not changed since then.
Changes from V1:
1. No pinning of processes within cgroupns. Tasks can be freely moved
across cgroups even outside of their cgroupns-root. Usual DAC/MAC policies
apply as before.
2. Path in /proc/<pid>/cgroup is now always shown and is relative to
cgroupns-root. So path can contain '/..' strings depending on cgroupns-root
of the reader and cgroup of <pid>.
3. setns() does not require the process to first move under target
cgroupns-root.
Changes form RFC (V0):
1. setns support for cgroupns
2. 'mount -t cgroup cgroup <mntpt>' from inside a cgroupns now
mounts the cgroup hierarcy with cgroupns-root as the filesystem root.
3. writes to cgroup files outside of cgroupns-root are not allowed
4. visibility of /proc/<pid>/cgroup is further restricted by not showing
anything if the <pid> is in a sibling cgroupns and its cgroup falls outside
your cgroupns-root.
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [next] | [standalone]
| From | serge.hallyn@ubuntu.com |
|---|---|
| Date | 2015-11-27 22:00 +0100 |
| Subject | [PATCH 6/7] cgroup: Add documentation for cgroup namespaces |
| Message-ID | <qzyhA-7Kz-23@gated-at.bofh.it> |
| In reply to | #1278963 |
From: Aditya Kali <adityakali@google.com>
Signed-off-by: Aditya Kali <adityakali@google.com>
Signed-off-by: Serge Hallyn <serge.hallyn@ubuntu.com>
---
Documentation/cgroups/namespace.txt | 142 +++++++++++++++++++++++++++++++++++
1 file changed, 142 insertions(+)
create mode 100644 Documentation/cgroups/namespace.txt
diff --git a/Documentation/cgroups/namespace.txt b/Documentation/cgroups/namespace.txt
new file mode 100644
index 0000000..a5b80e8
--- /dev/null
+++ b/Documentation/cgroups/namespace.txt
@@ -0,0 +1,142 @@
+ CGroup Namespaces
+
+CGroup Namespace provides a mechanism to virtualize the view of the
+/proc/<pid>/cgroup file. The CLONE_NEWCGROUP clone-flag can be used with
+clone() and unshare() syscalls to create a new cgroup namespace.
+The process running inside the cgroup namespace will have its /proc/<pid>/cgroup
+output restricted to cgroupns-root. cgroupns-root is the cgroup of the process
+at the time of creation of the cgroup namespace.
+
+Prior to CGroup Namespace, the /proc/<pid>/cgroup file used to show complete
+path of the cgroup of a process. In a container setup (where a set of cgroups
+and namespaces are intended to isolate processes), the /proc/<pid>/cgroup file
+may leak potential system level information to the isolated processes.
+
+For Example:
+ $ cat /proc/self/cgroup
+ 0:cpuset,cpu,cpuacct,memory,devices,freezer,hugetlb:/batchjobs/container_id1
+
+The path '/batchjobs/container_id1' can generally be considered as system-data
+and its desirable to not expose it to the isolated process.
+
+CGroup Namespaces can be used to restrict visibility of this path.
+For Example:
+ # Before creating cgroup namespace
+ $ ls -l /proc/self/ns/cgroup
+ lrwxrwxrwx 1 root root 0 2014-07-15 10:37 /proc/self/ns/cgroup -> cgroup:[4026531835]
+ $ cat /proc/self/cgroup
+ 0:cpuset,cpu,cpuacct,memory,devices,freezer,hugetlb:/batchjobs/container_id1
+
+ # unshare(CLONE_NEWCGROUP) and exec /bin/bash
+ $ ~/unshare -c
+ [ns]$ ls -l /proc/self/ns/cgroup
+ lrwxrwxrwx 1 root root 0 2014-07-15 10:35 /proc/self/ns/cgroup -> cgroup:[4026532183]
+ # From within new cgroupns, process sees that its in the root cgroup
+ [ns]$ cat /proc/self/cgroup
+ 0:cpuset,cpu,cpuacct,memory,devices,freezer,hugetlb:/
+
+ # From global cgroupns:
+ $ cat /proc/<pid>/cgroup
+ 0:cpuset,cpu,cpuacct,memory,devices,freezer,hugetlb:/batchjobs/container_id1
+
+ # Unshare cgroupns along with userns and mountns
+ # Following calls unshare(CLONE_NEWCGROUP|CLONE_NEWUSER|CLONE_NEWNS), then
+ # sets up uid/gid map and execs /bin/bash
+ $ ~/unshare -c -u -m
+ # Originally, we were in /batchjobs/container_id1 cgroup. Mount our own cgroup
+ # hierarchy.
+ [ns]$ mount -t cgroup cgroup /tmp/cgroup
+ [ns]$ ls -l /tmp/cgroup
+ total 0
+ -r--r--r-- 1 root root 0 2014-10-13 09:32 cgroup.controllers
+ -r--r--r-- 1 root root 0 2014-10-13 09:32 cgroup.populated
+ -rw-r--r-- 1 root root 0 2014-10-13 09:25 cgroup.procs
+ -rw-r--r-- 1 root root 0 2014-10-13 09:32 cgroup.subtree_control
+
+The cgroupns-root (/batchjobs/container_id1 in above example) becomes the
+filesystem root for the namespace specific cgroupfs mount.
+
+The virtualization of /proc/self/cgroup file combined with restricting
+the view of cgroup hierarchy by namespace-private cgroupfs mount
+should provide a completely isolated cgroup view inside the container.
+
+In its current form, the cgroup namespaces patcheset provides following
+behavior:
+
+(1) The 'cgroupns-root' for a cgroup namespace is the cgroup in which
+ the process calling unshare is running.
+ For ex. if a process in /batchjobs/container_id1 cgroup calls unshare,
+ cgroup /batchjobs/container_id1 becomes the cgroupns-root.
+ For the init_cgroup_ns, this is the real root ('/') cgroup
+ (identified in code as cgrp_dfl_root.cgrp).
+
+(2) The cgroupns-root cgroup does not change even if the namespace
+ creator process later moves to a different cgroup.
+ $ ~/unshare -c # unshare cgroupns in some cgroup
+ [ns]$ cat /proc/self/cgroup
+ 0:cpuset,cpu,cpuacct,memory,devices,freezer,hugetlb:/
+ [ns]$ mkdir sub_cgrp_1
+ [ns]$ echo 0 > sub_cgrp_1/cgroup.procs
+ [ns]$ cat /proc/self/cgroup
+ 0:cpuset,cpu,cpuacct,memory,devices,freezer,hugetlb:/sub_cgrp_1
+
+(3) Each process gets its CGROUPNS specific view of /proc/<pid>/cgroup
+(a) Processes running inside the cgroup namespace will be able to see
+ cgroup paths (in /proc/self/cgroup) only inside their root cgroup
+ [ns]$ sleep 100000 & # From within unshared cgroupns
+ [1] 7353
+ [ns]$ echo 7353 > sub_cgrp_1/cgroup.procs
+ [ns]$ cat /proc/7353/cgroup
+ 0:cpuset,cpu,cpuacct,memory,devices,freezer,hugetlb:/sub_cgrp_1
+
+(b) From global cgroupns, the real cgroup path will be visible:
+ $ cat /proc/7353/cgroup
+ 0:cpuset,cpu,cpuacct,memory,devices,freezer,hugetlb:/batchjobs/container_id1/sub_cgrp_1
+
+(c) From a sibling cgroupns (cgroupns root-ed at a different cgroup), cgroup
+ path relative to its own cgroupns-root will be shown:
+ # ns2's cgroupns-root is at '/batchjobs/container_id2'
+ [ns2]$ cat /proc/7353/cgroup
+ 0:cpuset,cpu,cpuacct,memory,devices,freezer,hugetlb:/../container_id2/sub_cgrp_1
+
+ Note that the relative path always starts with '/' to indicate that its
+ relative to the cgroupns-root of the caller.
+
+(4) Processes inside a cgroupns can move in-and-out of the cgroupns-root
+ (if they have proper access to external cgroups).
+ # From inside cgroupns (with cgroupns-root at /batchjobs/container_id1), and
+ # assuming that the global hierarchy is still accessible inside cgroupns:
+ $ cat /proc/7353/cgroup
+ 0:cpuset,cpu,cpuacct,memory,devices,freezer,hugetlb:/sub_cgrp_1
+ $ echo 7353 > batchjobs/container_id2/cgroup.procs
+ $ cat /proc/7353/cgroup
+ 0:cpuset,cpu,cpuacct,memory,devices,freezer,hugetlb:/../container_id2
+
+ Note that this kind of setup is not encouraged. A task inside cgroupns
+ should only be exposed to its own cgroupns hierarchy. Otherwise it makes
+ the virtualization of /proc/<pid>/cgroup less useful.
+
+(5) Setns to another cgroup namespace is allowed when:
+ (a) the process has CAP_SYS_ADMIN in its current userns
+ (b) the process has CAP_SYS_ADMIN in the target cgroupns' userns
+ No implicit cgroup changes happen with attaching to another cgroupns. It
+ is expected that the somone moves the attaching process under the target
+ cgroupns-root.
+
+(6) When some thread from a multi-threaded process unshares its
+ cgroup-namespace, the new cgroupns gets applied to the entire process (all
+ the threads). For the unified-hierarchy this is expected as it only allows
+ process-level containerization. For the legacy hierarchies this may be
+ unexpected. So all the threads in the process will have the same cgroup.
+
+(7) The cgroup namespace is alive as long as there is atleast 1
+ process inside it. When the last process exits, the cgroup
+ namespace is destroyed. The cgroupns-root and the actual cgroups
+ remain though.
+
+(8) Namespace specific cgroup hierarchy can be mounted by a process running
+ inside cgroupns:
+ $ mount -t cgroup -o __DEVEL__sane_behavior cgroup $MOUNT_POINT
+
+ This will mount the unified cgroup hierarchy with cgroupns-root as the
+ filesystem root. The process needs CAP_SYS_ADMIN in its userns and mntns.
--
1.7.9.5
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | serge.hallyn@ubuntu.com |
|---|---|
| Date | 2015-11-27 22:00 +0100 |
| Subject | [PATCH 5/7] cgroup: mount cgroupns-root when inside non-init cgroupns |
| Message-ID | <qzyhA-7Kz-25@gated-at.bofh.it> |
| In reply to | #1278963 |
From: Aditya Kali <adityakali@google.com>
This patch enables cgroup mounting inside userns when a process
as appropriate privileges. The cgroup filesystem mounted is
rooted at the cgroupns-root. Thus, in a container-setup, only
the hierarchy under the cgroupns-root is exposed inside the container.
This allows container management tools to run inside the containers
without depending on any global state.
In order to support this, a new kernfs api is added to lookup the
dentry for the cgroupns-root.
Changelog:
20151116 - Don't allow user namespaces to bind new subsystems
20151118 - postpone the FS_USERNS_MOUNT flag until the
last patch, until we can convince ourselves it
is safe.
Signed-off-by: Aditya Kali <adityakali@google.com>
Acked-by: Serge E. Hallyn <serge.hallyn@ubuntu.com>
---
fs/kernfs/mount.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++
include/linux/kernfs.h | 2 ++
kernel/cgroup.c | 39 ++++++++++++++++++++++++++++++++++++-
3 files changed, 90 insertions(+), 1 deletion(-)
diff --git a/fs/kernfs/mount.c b/fs/kernfs/mount.c
index 8eaf417..cc41fe1 100644
--- a/fs/kernfs/mount.c
+++ b/fs/kernfs/mount.c
@@ -62,6 +62,56 @@ struct kernfs_root *kernfs_root_from_sb(struct super_block *sb)
return NULL;
}
+/**
+ * kernfs_obtain_root - get a dentry for the given kernfs_node
+ * @sb: the kernfs super_block
+ * @kn: kernfs_node for which a dentry is needed
+ *
+ * This can be used by callers which want to mount only a part of the kernfs
+ * as root of the filesystem.
+ */
+struct dentry *kernfs_obtain_root(struct super_block *sb,
+ struct kernfs_node *kn)
+{
+ struct dentry *dentry;
+ struct inode *inode;
+
+ BUG_ON(sb->s_op != &kernfs_sops);
+
+ /* inode for the given kernfs_node should already exist. */
+ inode = kernfs_get_inode(sb, kn);
+ if (!inode) {
+ pr_debug("kernfs: could not get inode for '");
+ pr_cont_kernfs_path(kn);
+ pr_cont("'.\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ /* instantiate and link root dentry */
+ dentry = d_obtain_root(inode);
+ if (!dentry) {
+ pr_debug("kernfs: could not get dentry for '");
+ pr_cont_kernfs_path(kn);
+ pr_cont("'.\n");
+ return ERR_PTR(-ENOMEM);
+ }
+
+ /*
+ * If this is a new dentry, set it up. We need kernfs_mutex because
+ * this may be called by callers other than kernfs_fill_super.
+ */
+ mutex_lock(&kernfs_mutex);
+ if (!dentry->d_fsdata) {
+ kernfs_get(kn);
+ dentry->d_fsdata = kn;
+ } else {
+ WARN_ON(dentry->d_fsdata != kn);
+ }
+ mutex_unlock(&kernfs_mutex);
+
+ return dentry;
+}
+
static int kernfs_fill_super(struct super_block *sb, unsigned long magic)
{
struct kernfs_super_info *info = kernfs_info(sb);
diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h
index d025ebd..1903777 100644
--- a/include/linux/kernfs.h
+++ b/include/linux/kernfs.h
@@ -284,6 +284,8 @@ struct kernfs_node *kernfs_node_from_dentry(struct dentry *dentry);
struct kernfs_root *kernfs_root_from_sb(struct super_block *sb);
struct inode *kernfs_get_inode(struct super_block *sb, struct kernfs_node *kn);
+struct dentry *kernfs_obtain_root(struct super_block *sb,
+ struct kernfs_node *kn);
struct kernfs_root *kernfs_create_root(struct kernfs_syscall_ops *scops,
unsigned int flags, void *priv);
void kernfs_destroy_root(struct kernfs_root *root);
diff --git a/kernel/cgroup.c b/kernel/cgroup.c
index 0afed6b..2f487a4 100644
--- a/kernel/cgroup.c
+++ b/kernel/cgroup.c
@@ -2005,6 +2005,15 @@ static struct dentry *cgroup_mount(struct file_system_type *fs_type,
int ret;
int i;
bool new_sb;
+ struct cgroup_namespace *ns = current->nsproxy->cgroup_ns;
+
+ get_cgroup_ns(ns);
+
+ /* Check if the caller has permission to mount. */
+ if (!ns_capable(ns->user_ns, CAP_SYS_ADMIN)) {
+ put_cgroup_ns(ns);
+ return ERR_PTR(-EPERM);
+ }
/*
* The first time anyone tries to mount a cgroup, enable the list
@@ -2121,6 +2130,11 @@ static struct dentry *cgroup_mount(struct file_system_type *fs_type,
goto out_unlock;
}
+ if (!opts.none && !capable(CAP_SYS_ADMIN)) {
+ ret = -EPERM;
+ goto out_unlock;
+ }
+
root = kzalloc(sizeof(*root), GFP_KERNEL);
if (!root) {
ret = -ENOMEM;
@@ -2139,12 +2153,34 @@ out_free:
kfree(opts.release_agent);
kfree(opts.name);
- if (ret)
+ if (ret) {
+ put_cgroup_ns(ns);
return ERR_PTR(ret);
+ }
+
out_mount:
dentry = kernfs_mount(fs_type, flags, root->kf_root,
is_v2 ? CGROUP2_SUPER_MAGIC : CGROUP_SUPER_MAGIC,
&new_sb);
+
+ if (!IS_ERR(dentry)) {
+ /*
+ * In non-init cgroup namespace, instead of root cgroup's
+ * dentry, we return the dentry corresponding to the
+ * cgroupns->root_cgrp.
+ */
+ if (ns != &init_cgroup_ns) {
+ struct dentry *nsdentry;
+ struct cgroup *cgrp;
+
+ cgrp = cset_cgroup_from_root(ns->root_cset, root);
+ nsdentry = kernfs_obtain_root(dentry->d_sb,
+ cgrp->kn);
+ dput(dentry);
+ dentry = nsdentry;
+ }
+ }
+
if (IS_ERR(dentry) || !new_sb)
cgroup_put(&root->cgrp);
@@ -2157,6 +2193,7 @@ out_mount:
deactivate_super(pinned_sb);
}
+ put_cgroup_ns(ns);
return dentry;
}
--
1.7.9.5
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [standalone]
Back to top | Article view | linux.kernel
csiph-web