cgroups: if you list_empty() a head then don't list_del() it
list_del() leaves poison in the prev and next pointers. The next list_empty() will compare those poisons, and say the list isn't empty. Any list operations that assume the node is on a list because of such a check will be fooled into dereferencing poison. One needs to INIT the node after the del, and fortunately there's already a wrapper for that - list_del_init(). Some of the dels are followed by deallocations, so can be ignored, and one can be merged with an add to make a move. Apart from that, I erred on the side of caution in making nodes list_empty()-queriable. Signed-off-by: Phil Carmody <ext-phil.2.carmody@nokia.com> Reviewed-by: Paul Menage <menage@google.com> Cc: Li Zefan <lizf@cn.fujitsu.com> Acked-by: Kirill A. Shutemov <kirill@shutemov.name> Cc: <stable@kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
committed by
Linus Torvalds
parent
edd45544c6
commit
8d2587970b
@@ -1813,10 +1813,8 @@ int cgroup_attach_task(struct cgroup *cgrp, struct task_struct *tsk)
|
|||||||
|
|
||||||
/* Update the css_set linked lists if we're using them */
|
/* Update the css_set linked lists if we're using them */
|
||||||
write_lock(&css_set_lock);
|
write_lock(&css_set_lock);
|
||||||
if (!list_empty(&tsk->cg_list)) {
|
if (!list_empty(&tsk->cg_list))
|
||||||
list_del(&tsk->cg_list);
|
list_move(&tsk->cg_list, &newcg->tasks);
|
||||||
list_add(&tsk->cg_list, &newcg->tasks);
|
|
||||||
}
|
|
||||||
write_unlock(&css_set_lock);
|
write_unlock(&css_set_lock);
|
||||||
|
|
||||||
for_each_subsys(root, ss) {
|
for_each_subsys(root, ss) {
|
||||||
@@ -3655,12 +3653,12 @@ again:
|
|||||||
spin_lock(&release_list_lock);
|
spin_lock(&release_list_lock);
|
||||||
set_bit(CGRP_REMOVED, &cgrp->flags);
|
set_bit(CGRP_REMOVED, &cgrp->flags);
|
||||||
if (!list_empty(&cgrp->release_list))
|
if (!list_empty(&cgrp->release_list))
|
||||||
list_del(&cgrp->release_list);
|
list_del_init(&cgrp->release_list);
|
||||||
spin_unlock(&release_list_lock);
|
spin_unlock(&release_list_lock);
|
||||||
|
|
||||||
cgroup_lock_hierarchy(cgrp->root);
|
cgroup_lock_hierarchy(cgrp->root);
|
||||||
/* delete this cgroup from parent->children */
|
/* delete this cgroup from parent->children */
|
||||||
list_del(&cgrp->sibling);
|
list_del_init(&cgrp->sibling);
|
||||||
cgroup_unlock_hierarchy(cgrp->root);
|
cgroup_unlock_hierarchy(cgrp->root);
|
||||||
|
|
||||||
d = dget(cgrp->dentry);
|
d = dget(cgrp->dentry);
|
||||||
@@ -3879,7 +3877,7 @@ void cgroup_unload_subsys(struct cgroup_subsys *ss)
|
|||||||
subsys[ss->subsys_id] = NULL;
|
subsys[ss->subsys_id] = NULL;
|
||||||
|
|
||||||
/* remove subsystem from rootnode's list of subsystems */
|
/* remove subsystem from rootnode's list of subsystems */
|
||||||
list_del(&ss->sibling);
|
list_del_init(&ss->sibling);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* disentangle the css from all css_sets attached to the dummytop. as
|
* disentangle the css from all css_sets attached to the dummytop. as
|
||||||
@@ -4241,7 +4239,7 @@ void cgroup_exit(struct task_struct *tsk, int run_callbacks)
|
|||||||
if (!list_empty(&tsk->cg_list)) {
|
if (!list_empty(&tsk->cg_list)) {
|
||||||
write_lock(&css_set_lock);
|
write_lock(&css_set_lock);
|
||||||
if (!list_empty(&tsk->cg_list))
|
if (!list_empty(&tsk->cg_list))
|
||||||
list_del(&tsk->cg_list);
|
list_del_init(&tsk->cg_list);
|
||||||
write_unlock(&css_set_lock);
|
write_unlock(&css_set_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user