cgroups: fix cgroup_iter_next() bug.
PATCH 1/1 cgroups: fix cgroup_iter_next() bug.
we access to res->cgroups without the task_lock(), so res->cgroups may be changed. it's unreliable, and "if (l == &res->cgroups->tasks)" may be false forever.
we don't need add any lock for fixing this bug. we just access to struct css_set by struct cg_cgroup_link, not by struct task_struct.
since we hold css_set_lock, struct cg_cgroup_link is reliable.
---
kernel/cgroup.c +3 -1
@@ -1810,6 +1819,7 @@ struct task_struct *cgroup_iter_next(struct cgroup *cgrp, {struct task_struct *res;struct list_head *l = it->task; +struct cg_cgroup_link *link;/* If the iterator cg is NULL, we have no tasks */ if (!it->cg_link)
@@ -1817,7 +1827,8 @@ struct task_struct *cgroup_iter_next(struct cgroup *cgrp, res = list_entry(l, struct task_struct, cg_list);/* Advance iterator to find next entry */ l = l->next; -if (l == &res->cgroups->tasks) { + link = list_entry(it->cg_link, struct cg_cgroup_link, cgrp_link_list); +if (l == &link->cg->tasks) {/* We reached the end of this task list - move on to * the next cg_cgroup_link */ cgroup_advance_iter (cgrp, it);
A message that is not in the archive (sent off-list or not yet received): [email protected]
Paul Menage
Reviewed-byQuoted 11 lines · Lai Jiangshan
we access to
res->cgroupswithout thetask_lock(), sores->cgroupsmay be changed. it's unreliable, and "if (l ==&res->cgroups->tasks)" may be false forever.we don't need add any lock for fixing this bug. we just access to struct
css_setby structcg_cgroup_link, not by structtask_struct.since we hold
css_set_lock, structcg_cgroup_linkis reliable.Signed-off-by Lai Jiangshan <[email protected]>
Sounds plausible - you'd need to have thread A have completed the call to find_css_set() and then have the iteration begin in thread B, so it's a pretty tight race. But accessing through the cs_cgroup_link is probably conceptually better anyway, regardless of races.
Thanks.
Quoted 26 lines
---
kernel/cgroup.c +3
-1@@ -1810,6 +1819,7 @@ struct task_struct *cgroup_iter_next(struct cgroup *cgrp, {struct task_struct *res;struct list_head *l = it->task; +struct cg_cgroup_link *link;/* If the iterator cg is NULL, we have no tasks */ if (!it->cg_link)@@ -1817,7 +1827,8 @@ struct task_struct *cgroup_iter_next(struct cgroup *cgrp, res = list_entry(l, struct task_struct, cg_list);/* Advance iterator to find next entry */ l = l->next; -if (l == &res->cgroups->tasks) { + link = list_entry(it->cg_link, struct cg_cgroup_link, cgrp_link_list); +if (l == &link->cg->tasks) {/* We reached the end of this task list - move on to * the next cg_cgroup_link */ cgroup_advance_iter (cgrp, it);
Quoted 11 lines · Lai Jiangshan
we access to
res->cgroupswithout thetask_lock(), sores->cgroupsmay be changed. it's unreliable, and "if (l ==&res->cgroups->tasks)" may be false forever.we don't need add any lock for fixing this bug. we just access to struct
css_setby structcg_cgroup_link, not by structtask_struct.since we hold
css_set_lock, structcg_cgroup_linkis reliable.Signed-off-by Lai Jiangshan <[email protected]>
Sounds plausible - you'd need to have thread A have completed the call to find_css_set() and then have the iteration begin in thread B, so it's a pretty tight race. But accessing through the cs_cgroup_link is probably conceptually better anyway, regardless of races.
Thanks.
Quoted 26 lines
---
kernel/cgroup.c +3
-1@@ -1810,6 +1819,7 @@ struct task_struct *cgroup_iter_next(struct cgroup *cgrp, {struct task_struct *res;struct list_head *l = it->task; +struct cg_cgroup_link *link;/* If the iterator cg is NULL, we have no tasks */ if (!it->cg_link)@@ -1817,7 +1827,8 @@ struct task_struct *cgroup_iter_next(struct cgroup *cgrp, res = list_entry(l, struct task_struct, cg_list);/* Advance iterator to find next entry */ l = l->next; -if (l == &res->cgroups->tasks) { + link = list_entry(it->cg_link, struct cg_cgroup_link, cgrp_link_list); +if (l == &link->cg->tasks) {/* We reached the end of this task list - move on to * the next cg_cgroup_link */ cgroup_advance_iter (cgrp, it);