Skip to content

Commit 7b8a321

Browse files
htejungregkh
authored andcommitted
cgroup: fix cgroup_create() error handling path
commit 266ccd5 upstream. ae7f164 ("cgroup: move cgroup->subsys[] assignment to online_css()") moved cgroup->subsys[] assignements later in cgroup_create() but didn't update error handling path accordingly leading to the following oops and leaking later css's after an online_css() failure. The oops is from cgroup destruction path being invoked on the partially constructed cgroup which is not ready to handle empty slots in cgrp->subsys[] array. BUG: unable to handle kernel NULL pointer dereference at 0000000000000008 IP: [<ffffffff810eeaa8>] cgroup_destroy_locked+0x118/0x2f0 PGD a780a067 PUD aadbe067 PMD 0 Oops: 0000 [#1] SMP Modules linked in: CPU: 6 PID: 7360 Comm: mkdir Not tainted 3.13.0-rc2+ #69 Hardware name: task: ffff8800b9dbec00 ti: ffff8800a781a000 task.ti: ffff8800a781a000 RIP: 0010:[<ffffffff810eeaa8>] [<ffffffff810eeaa8>] cgroup_destroy_locked+0x118/0x2f0 RSP: 0018:ffff8800a781bd98 EFLAGS: 00010282 RAX: ffff880586903878 RBX: ffff880586903800 RCX: ffff880586903820 RDX: ffff880586903860 RSI: ffff8800a781bdb0 RDI: ffff880586903820 RBP: ffff8800a781bde8 R08: ffff88060e0b8048 R09: ffffffff811d7bc1 R10: 000000000000008c R11: 0000000000000001 R12: ffff8800a72286c0 R13: 0000000000000000 R14: ffffffff81cf7a40 R15: 0000000000000001 FS: 00007f60ecda57a0(0000) GS:ffff8806272c0000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000000000008 CR3: 00000000a7a03000 CR4: 00000000000007e0 Stack: ffff880586903860 ffff880586903910 ffff8800a72286c0 ffff880586903820 ffffffff81cf7a40 ffff880586903800 ffff88060e0b8018 ffffffff81cf7a40 ffff8800b9dbec00 ffff8800b9dbf098 ffff8800a781bec8 ffffffff810ef5bf Call Trace: [<ffffffff810ef5bf>] cgroup_mkdir+0x55f/0x5f0 [<ffffffff811c90ae>] vfs_mkdir+0xee/0x140 [<ffffffff811cb07e>] SyS_mkdirat+0x6e/0xf0 [<ffffffff811c6a19>] SyS_mkdir+0x19/0x20 [<ffffffff8169e569>] system_call_fastpath+0x16/0x1b This patch moves reference bumping inside online_css() loop, clears css_ar[] as css's are brought online successfully, and updates err_destroy path so that either a css is fully online and destroyed by cgroup_destroy_locked() or the error path frees it. This creates a duplicate css free logic in the error path but it will be cleaned up soon. v2: Li pointed out that cgroup_destroy_locked() would do NULL-deref if invoked with a cgroup which doesn't have all css's populated. Update cgroup_destroy_locked() so that it skips NULL css's. Signed-off-by: Tejun Heo <[email protected]> Acked-by: Li Zefan <[email protected]> Reported-by: Vladimir Davydov <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 43ed0ac commit 7b8a321

File tree

1 file changed

+21
-10
lines changed

1 file changed

+21
-10
lines changed

kernel/cgroup.c

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4490,14 +4490,6 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry,
44904490
list_add_tail_rcu(&cgrp->sibling, &cgrp->parent->children);
44914491
root->number_of_cgroups++;
44924492

4493-
/* each css holds a ref to the cgroup's dentry and the parent css */
4494-
for_each_root_subsys(root, ss) {
4495-
struct cgroup_subsys_state *css = css_ar[ss->subsys_id];
4496-
4497-
dget(dentry);
4498-
css_get(css->parent);
4499-
}
4500-
45014493
/* hold a ref to the parent's dentry */
45024494
dget(parent->dentry);
45034495

@@ -4509,6 +4501,13 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry,
45094501
if (err)
45104502
goto err_destroy;
45114503

4504+
/* each css holds a ref to the cgroup's dentry and parent css */
4505+
dget(dentry);
4506+
css_get(css->parent);
4507+
4508+
/* mark it consumed for error path */
4509+
css_ar[ss->subsys_id] = NULL;
4510+
45124511
if (ss->broken_hierarchy && !ss->warned_broken_hierarchy &&
45134512
parent->parent) {
45144513
pr_warning("cgroup: %s (%d) created nested cgroup for controller \"%s\" which has incomplete hierarchy support. Nested cgroups may change behavior in the future.\n",
@@ -4555,6 +4554,14 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry,
45554554
return err;
45564555

45574556
err_destroy:
4557+
for_each_root_subsys(root, ss) {
4558+
struct cgroup_subsys_state *css = css_ar[ss->subsys_id];
4559+
4560+
if (css) {
4561+
percpu_ref_cancel_init(&css->refcnt);
4562+
ss->css_free(css);
4563+
}
4564+
}
45584565
cgroup_destroy_locked(cgrp);
45594566
mutex_unlock(&cgroup_mutex);
45604567
mutex_unlock(&dentry->d_inode->i_mutex);
@@ -4716,8 +4723,12 @@ static int cgroup_destroy_locked(struct cgroup *cgrp)
47164723
* will be invoked to perform the rest of destruction once the
47174724
* percpu refs of all css's are confirmed to be killed.
47184725
*/
4719-
for_each_root_subsys(cgrp->root, ss)
4720-
kill_css(cgroup_css(cgrp, ss));
4726+
for_each_root_subsys(cgrp->root, ss) {
4727+
struct cgroup_subsys_state *css = cgroup_css(cgrp, ss);
4728+
4729+
if (css)
4730+
kill_css(css);
4731+
}
47214732

47224733
/*
47234734
* Mark @cgrp dead. This prevents further task migration and child

0 commit comments

Comments
 (0)