提交 6b6c3fb5 编写于 作者: T Tejun Heo 提交者: Yang Yingliang

cgroup: Use open-time cgroup namespace for process migration perm checks

mainline inclusion
from mainline-v5.16
commit e5745764
category: bugfix
bugzilla: NA
CVE: CVE-2021-4197

------------------------------------------------------------------------

cgroup process migration permission checks are performed at write time as
whether a given operation is allowed or not is dependent on the content of
the write - the PID. This currently uses current's cgroup namespace which is
a potential security weakness as it may allow scenarios where a less
privileged process tricks a more privileged one into writing into a fd that
it created.

This patch makes cgroup remember the cgroup namespace at the time of open
and uses it for migration permission checks instad of current's. Note that
this only applies to cgroup2 as cgroup1 doesn't have namespace support.

This also fixes a use-after-free bug on cgroupns reported in

 https://lore.kernel.org/r/00000000000048c15c05d0083397@google.com

Note that backporting this fix also requires the preceding patch.
Reported-by: N"Eric W. Biederman" <ebiederm@xmission.com>
Suggested-by: NLinus Torvalds <torvalds@linuxfoundation.org>
Cc: Michal Koutný <mkoutny@suse.com>
Cc: Oleg Nesterov <oleg@redhat.com>
Reviewed-by: NMichal Koutný <mkoutny@suse.com>
Reported-by: syzbot+50f5cf33a284ce738b62@syzkaller.appspotmail.com
Link: https://lore.kernel.org/r/00000000000048c15c05d0083397@google.com
Fixes: 5136f636 ("cgroup: implement "nsdelegate" mount option")
Signed-off-by: NTejun Heo <tj@kernel.org>
Conflicts:
	kernel/cgroup/cgroup-internal.h
	kernel/cgroup/cgroup.c
Signed-off-by: NLu Jialin <lujialin4@huawei.com>
Reviewed-by: Nweiyang wang <wangweiyang2@huawei.com>
Signed-off-by: NYang Yingliang <yangyingliang@huawei.com>
上级 75acfe71
......@@ -37,6 +37,8 @@ extern char trace_cgroup_path[TRACE_CGROUP_PATH_LEN];
struct cgroup_pidlist;
struct cgroup_file_ctx {
struct cgroup_namespace *ns;
struct {
bool started;
struct css_task_iter iter;
......
......@@ -3483,14 +3483,19 @@ static int cgroup_file_open(struct kernfs_open_file *of)
ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
if (!ctx)
return -ENOMEM;
ctx->ns = current->nsproxy->cgroup_ns;
get_cgroup_ns(ctx->ns);
of->priv = ctx;
if (!cft->open)
return 0;
ret = cft->open(of);
if (ret)
if (ret) {
put_cgroup_ns(ctx->ns);
kfree(ctx);
}
return ret;
}
......@@ -3501,13 +3506,14 @@ static void cgroup_file_release(struct kernfs_open_file *of)
if (cft->release)
cft->release(of);
put_cgroup_ns(ctx->ns);
kfree(ctx);
}
static ssize_t cgroup_file_write(struct kernfs_open_file *of, char *buf,
size_t nbytes, loff_t off)
{
struct cgroup_namespace *ns = current->nsproxy->cgroup_ns;
struct cgroup_file_ctx *ctx = of->priv;
struct cgroup *cgrp = of->kn->parent->priv;
struct cftype *cft = of->kn->priv;
struct cgroup_subsys_state *css;
......@@ -3521,7 +3527,7 @@ static ssize_t cgroup_file_write(struct kernfs_open_file *of, char *buf,
*/
if ((cgrp->root->flags & CGRP_ROOT_NS_DELEGATE) &&
!(cft->flags & CFTYPE_NS_DELEGATABLE) &&
ns != &init_cgroup_ns && ns->root_cset->dfl_cgrp == cgrp)
ctx->ns != &init_cgroup_ns && ctx->ns->root_cset->dfl_cgrp == cgrp)
return -EPERM;
if (cft->write)
......@@ -4483,9 +4489,9 @@ static int cgroup_procs_show(struct seq_file *s, void *v)
static int cgroup_procs_write_permission(struct cgroup *src_cgrp,
struct cgroup *dst_cgrp,
struct super_block *sb)
struct super_block *sb,
struct cgroup_namespace *ns)
{
struct cgroup_namespace *ns = current->nsproxy->cgroup_ns;
struct cgroup *com_cgrp = src_cgrp;
struct inode *inode;
int ret;
......@@ -4521,6 +4527,7 @@ static int cgroup_procs_write_permission(struct cgroup *src_cgrp,
static ssize_t cgroup_procs_write(struct kernfs_open_file *of,
char *buf, size_t nbytes, loff_t off)
{
struct cgroup_file_ctx *ctx = of->priv;
struct cgroup *src_cgrp, *dst_cgrp;
struct task_struct *task;
const struct cred *saved_cred;
......@@ -4548,7 +4555,8 @@ static ssize_t cgroup_procs_write(struct kernfs_open_file *of,
saved_cred = override_creds(of->file->f_cred);
ret = cgroup_procs_write_permission(src_cgrp, dst_cgrp,
of->file->f_path.dentry->d_sb);
of->file->f_path.dentry->d_sb,
ctx->ns);
revert_creds(saved_cred);
if (ret)
goto out_finish;
......@@ -4571,6 +4579,7 @@ static void *cgroup_threads_start(struct seq_file *s, loff_t *pos)
static ssize_t cgroup_threads_write(struct kernfs_open_file *of,
char *buf, size_t nbytes, loff_t off)
{
struct cgroup_file_ctx *ctx = of->priv;
struct cgroup *src_cgrp, *dst_cgrp;
struct task_struct *task;
const struct cred *saved_cred;
......@@ -4600,7 +4609,8 @@ static ssize_t cgroup_threads_write(struct kernfs_open_file *of,
saved_cred = override_creds(of->file->f_cred);
ret = cgroup_procs_write_permission(src_cgrp, dst_cgrp,
of->file->f_path.dentry->d_sb);
of->file->f_path.dentry->d_sb,
ctx->ns);
revert_creds(saved_cred);
if (ret)
goto out_finish;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册