kernfs_perms_start() takes kernfs_root(of->kn)->kernfs_rwsem to protect its walk, but of->kn is the cgroup file the seq sits on (ve.sysfs_permissions is a cgroup cftype), so that is the cgroup hierarchy rwsem, while the loop walks the sysfs tree (sysfs_root_kn), a different kernfs root. The sysfs tree walk and the ve_perms_map reads run under the wrong root rwsem and race concurrent sysfs node add and remove, a use-after-free.
Lock kernfs_root(root)->kernfs_rwsem, the tree actually being walked, and release the same lock in kernfs_perms_stop(), which now takes the root. https://virtuozzo.atlassian.net/browse/VSTOR-136541 Fixes: d0cb91d2dec2 ("ve/kernfs: fix kernfs locking in the control per-VE nodes visibility code") Signed-off-by: Mirian Shilakadze <[email protected]> Reviewed-by: Pavel Tikhomirov <[email protected]> --- fs/kernfs/ve.c | 14 ++++---------- fs/sysfs/ve.c | 2 +- include/linux/kernfs-ve.h | 2 +- 3 files changed, 6 insertions(+), 12 deletions(-) diff --git a/fs/kernfs/ve.c b/fs/kernfs/ve.c index f357ebb907f1..74676a9f0353 100644 --- a/fs/kernfs/ve.c +++ b/fs/kernfs/ve.c @@ -157,12 +157,10 @@ void *kernfs_perms_start(struct seq_file *m, loff_t *ppos, struct kernfs_node *root, struct kmapset_key *key) { struct ve_struct *ve = css_to_ve(seq_css(m)); - struct kernfs_open_file *of = m->private; - struct kernfs_node *kn = of->kn; - struct kernfs_root *root_for_sem = kernfs_root(kn); + struct kernfs_node *kn; loff_t pos = *ppos; - down_read(&root_for_sem->kernfs_rwsem); + down_read(&kernfs_root(root)->kernfs_rwsem); for (kn = root; kn; kn = kernfs_next_recursive(kn)) { if (kernfs_perms_shown(ve, kn, key) && !pos--) break; @@ -184,13 +182,9 @@ void *kernfs_perms_next(struct seq_file *m, void *v, loff_t *ppos, return kn; } -void kernfs_perms_stop(struct seq_file *m, void *v) +void kernfs_perms_stop(struct seq_file *m, void *v, struct kernfs_node *root) { - struct kernfs_open_file *of = m->private; - struct kernfs_node *kn = of->kn; - struct kernfs_root *root = kernfs_root(kn); - - up_read(&root->kernfs_rwsem); + up_read(&kernfs_root(root)->kernfs_rwsem); } int kernfs_perms_show(struct seq_file *m, void *v, struct kmapset_key *key) diff --git a/fs/sysfs/ve.c b/fs/sysfs/ve.c index eb941a1d5dd5..144a901547c0 100644 --- a/fs/sysfs/ve.c +++ b/fs/sysfs/ve.c @@ -55,7 +55,7 @@ static void *sysfs_perms_next(struct seq_file *m, void *v, loff_t *ppos) static void sysfs_perms_stop(struct seq_file *m, void *v) { - kernfs_perms_stop(m, v); + kernfs_perms_stop(m, v, sysfs_root_kn); mutex_unlock(&sysfs_perms_mutex); } diff --git a/include/linux/kernfs-ve.h b/include/linux/kernfs-ve.h index 2cb905918393..25837ff79e5b 100644 --- a/include/linux/kernfs-ve.h +++ b/include/linux/kernfs-ve.h @@ -24,7 +24,7 @@ void *kernfs_perms_start(struct seq_file *m, loff_t *ppos, struct kernfs_node *root, struct kmapset_key *key); void *kernfs_perms_next(struct seq_file *m, void *v, loff_t *ppos, struct kmapset_key *key); -void kernfs_perms_stop(struct seq_file *m, void *v); +void kernfs_perms_stop(struct seq_file *m, void *v, struct kernfs_node *root); int kernfs_perms_show(struct seq_file *m, void *v, struct kmapset_key *key); -- 2.43.0 _______________________________________________ Devel mailing list [email protected] https://lists.openvz.org/mailman/listinfo/devel
