From 0b58738a92c6f4159fe6edaf829c91c7d9cfc5e3 Mon Sep 17 00:00:00 2001 From: Jiufei Xue Date: Mon, 29 Jan 2018 17:29:51 +0800 Subject: [PATCH] fs/writeback: fix double free of blkcg_css MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We have gotten a WARNNING when releasing blkcg_css: [332489.681635] WARNING: CPU: 55 PID: 14859 at lib/list_debug.c:56 __list_del_entry+0x81/0xc0 [332489.682191] list_del corruption, ffff883e6b94d450->prev is LIST_POISON2 (dead000000000200) ...... [332489.683895] CPU: 55 PID: 14859 Comm: kworker/55:2 Tainted: G [332489.684477] Hardware name: Inspur SA5248M4/X10DRT-PS, BIOS 4.05A 10/11/2016 [332489.685061] Workqueue: cgroup_destroy css_release_work_fn [332489.685654]  ffffc9001d92bd28 ffffffff81380042 ffffc9001d92bd78 0000000000000000 [332489.686269]  ffffc9001d92bd68 ffffffff81088f8b 0000003800000000 ffff883e6b94d4a0 [332489.686867]  ffff883e6b94d400 ffffffff81ce8fe0 ffff88375b24f400 ffff883e6b94d4a0 [332489.687479] Call Trace: [332489.688078]  [] dump_stack+0x63/0x81 [332489.688681]  [] __warn+0xcb/0xf0 [332489.689276]  [] warn_slowpath_fmt+0x5f/0x80 [332489.689877]  [] __list_del_entry+0x81/0xc0 [332489.690481]  [] css_release_work_fn+0x42/0x140 [332489.691090]  [] process_one_work+0x189/0x420 [332489.691693]  [] worker_thread+0x4e/0x4b0 [332489.692293]  [] ? process_one_work+0x420/0x420 [332489.692905]  [] kthread+0xe6/0x100 [332489.693504]  [] ? kthread_park+0x60/0x60 [332489.694099]  [] ret_from_fork+0x41/0x50 [332489.694722] ---[ end trace 0cf869c4a5cfba87 ]--- ...... This is caused by calling css_get after the css is killed by another thread described below: Thread 1 Thread 2 cgroup_rmdir -> kill_css -> percpu_ref_kill_and_confirm -> css_killed_ref_fn css_killed_work_fn -> css_put -> css_release wb_get_create -> find_blkcg_css -> css_get -> css_put -> css_release (double free) -> css_release_workfn -> css_free_work_fn -> blkcg_css_free When doublefree happened, it may free the memory still used by other threads and cause a kernel panic. Fix this by using css_tryget_online in find_blkcg_css while will return false if the css is killed. Signed-off-by: Jiufei Xue Reviewed-by: Joseph Qi --- mm/backing-dev.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/mm/backing-dev.c b/mm/backing-dev.c index 13d945d2137f..de01892e13a5 100644 --- a/mm/backing-dev.c +++ b/mm/backing-dev.c @@ -583,15 +583,21 @@ static struct cgroup_subsys_state *find_blkcg_css(struct cgroup_subsys_state *me rcu_read_lock(); link = radix_tree_lookup(&memcg_blkcg_tree, memcg_css->id); - if (link) + if (link) { blkcg_css = link->blkcg_css; - else - blkcg_css = blkcg_root_css; + if (css_tryget_online(blkcg_css)) + goto out; + } + /* + * If not blkcg_root_css and tryget failed, + * get a reference of blkcg_root_css and return. + */ + blkcg_css = blkcg_root_css; css_get(blkcg_css); +out: rcu_read_unlock(); - return blkcg_css; } -- GitLab