Skip to content

Commit e574576

Browse files
committed
cgroup: Use open-time cgroup namespace for process migration perm checks
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/[email protected] Note that backporting this fix also requires the preceding patch. Reported-by: "Eric W. Biederman" <[email protected]> Suggested-by: Linus Torvalds <[email protected]> Cc: Michal Koutný <[email protected]> Cc: Oleg Nesterov <[email protected]> Reviewed-by: Michal Koutný <[email protected]> Reported-by: [email protected] Link: https://lore.kernel.org/r/[email protected] Fixes: 5136f63 ("cgroup: implement "nsdelegate" mount option") Signed-off-by: Tejun Heo <[email protected]>
1 parent 0d2b595 commit e574576

File tree

2 files changed

+21
-9
lines changed

2 files changed

+21
-9
lines changed

kernel/cgroup/cgroup-internal.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@ static inline struct cgroup_fs_context *cgroup_fc2context(struct fs_context *fc)
6868
struct cgroup_pidlist;
6969

7070
struct cgroup_file_ctx {
71+
struct cgroup_namespace *ns;
72+
7173
struct {
7274
void *trigger;
7375
} psi;

kernel/cgroup/cgroup.c

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3822,14 +3822,19 @@ static int cgroup_file_open(struct kernfs_open_file *of)
38223822
ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
38233823
if (!ctx)
38243824
return -ENOMEM;
3825+
3826+
ctx->ns = current->nsproxy->cgroup_ns;
3827+
get_cgroup_ns(ctx->ns);
38253828
of->priv = ctx;
38263829

38273830
if (!cft->open)
38283831
return 0;
38293832

38303833
ret = cft->open(of);
3831-
if (ret)
3834+
if (ret) {
3835+
put_cgroup_ns(ctx->ns);
38323836
kfree(ctx);
3837+
}
38333838
return ret;
38343839
}
38353840

@@ -3840,13 +3845,14 @@ static void cgroup_file_release(struct kernfs_open_file *of)
38403845

38413846
if (cft->release)
38423847
cft->release(of);
3848+
put_cgroup_ns(ctx->ns);
38433849
kfree(ctx);
38443850
}
38453851

38463852
static ssize_t cgroup_file_write(struct kernfs_open_file *of, char *buf,
38473853
size_t nbytes, loff_t off)
38483854
{
3849-
struct cgroup_namespace *ns = current->nsproxy->cgroup_ns;
3855+
struct cgroup_file_ctx *ctx = of->priv;
38503856
struct cgroup *cgrp = of->kn->parent->priv;
38513857
struct cftype *cft = of_cft(of);
38523858
struct cgroup_subsys_state *css;
@@ -3863,7 +3869,7 @@ static ssize_t cgroup_file_write(struct kernfs_open_file *of, char *buf,
38633869
*/
38643870
if ((cgrp->root->flags & CGRP_ROOT_NS_DELEGATE) &&
38653871
!(cft->flags & CFTYPE_NS_DELEGATABLE) &&
3866-
ns != &init_cgroup_ns && ns->root_cset->dfl_cgrp == cgrp)
3872+
ctx->ns != &init_cgroup_ns && ctx->ns->root_cset->dfl_cgrp == cgrp)
38673873
return -EPERM;
38683874

38693875
if (cft->write)
@@ -4853,9 +4859,9 @@ static int cgroup_may_write(const struct cgroup *cgrp, struct super_block *sb)
48534859

48544860
static int cgroup_procs_write_permission(struct cgroup *src_cgrp,
48554861
struct cgroup *dst_cgrp,
4856-
struct super_block *sb)
4862+
struct super_block *sb,
4863+
struct cgroup_namespace *ns)
48574864
{
4858-
struct cgroup_namespace *ns = current->nsproxy->cgroup_ns;
48594865
struct cgroup *com_cgrp = src_cgrp;
48604866
int ret;
48614867

@@ -4884,11 +4890,12 @@ static int cgroup_procs_write_permission(struct cgroup *src_cgrp,
48844890

48854891
static int cgroup_attach_permissions(struct cgroup *src_cgrp,
48864892
struct cgroup *dst_cgrp,
4887-
struct super_block *sb, bool threadgroup)
4893+
struct super_block *sb, bool threadgroup,
4894+
struct cgroup_namespace *ns)
48884895
{
48894896
int ret = 0;
48904897

4891-
ret = cgroup_procs_write_permission(src_cgrp, dst_cgrp, sb);
4898+
ret = cgroup_procs_write_permission(src_cgrp, dst_cgrp, sb, ns);
48924899
if (ret)
48934900
return ret;
48944901

@@ -4905,6 +4912,7 @@ static int cgroup_attach_permissions(struct cgroup *src_cgrp,
49054912
static ssize_t __cgroup_procs_write(struct kernfs_open_file *of, char *buf,
49064913
bool threadgroup)
49074914
{
4915+
struct cgroup_file_ctx *ctx = of->priv;
49084916
struct cgroup *src_cgrp, *dst_cgrp;
49094917
struct task_struct *task;
49104918
const struct cred *saved_cred;
@@ -4932,7 +4940,8 @@ static ssize_t __cgroup_procs_write(struct kernfs_open_file *of, char *buf,
49324940
*/
49334941
saved_cred = override_creds(of->file->f_cred);
49344942
ret = cgroup_attach_permissions(src_cgrp, dst_cgrp,
4935-
of->file->f_path.dentry->d_sb, threadgroup);
4943+
of->file->f_path.dentry->d_sb,
4944+
threadgroup, ctx->ns);
49364945
revert_creds(saved_cred);
49374946
if (ret)
49384947
goto out_finish;
@@ -6152,7 +6161,8 @@ static int cgroup_css_set_fork(struct kernel_clone_args *kargs)
61526161
goto err;
61536162

61546163
ret = cgroup_attach_permissions(cset->dfl_cgrp, dst_cgrp, sb,
6155-
!(kargs->flags & CLONE_THREAD));
6164+
!(kargs->flags & CLONE_THREAD),
6165+
current->nsproxy->cgroup_ns);
61566166
if (ret)
61576167
goto err;
61586168

0 commit comments

Comments
 (0)