kernfs_ve_permission() and kernfs_d_visible() walk the parent chain with
kernfs_parent(), which is rcu_dereference_check(kn->__parent, ...) and
requires the kernfs rwsem/rename_lock, a zero refcount, or an RCU
read-side critical section. They are called from the permission/lookup
path holding only kernfs_iattr_rwsem, so on a lockdep kernel this trips:

  WARNING: suspicious RCU usage
  fs/kernfs/kernfs-internal.h:131 suspicious rcu_dereference_check() usage!
  kernfs_ve_permission <- kernfs_iop_permission <- inode_permission

Wrap the parent walks in rcu_read_lock(); kernfs nodes are RCU-freed so
this is both correct (guards against concurrent reparent/free) and
silences the splat.

Fixes: cd9dd4ead86a ("ve/kernfs: implement ve-based permissions")
Feature: sysfs: per-CT entries visibility and permissions configuration
https://virtuozzo.atlassian.net/browse/VSTOR-137234
Signed-off-by: Konstantin Khorenko <[email protected]>
---
 fs/kernfs/ve.c | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/fs/kernfs/ve.c b/fs/kernfs/ve.c
index beaa278b014e..e83ee5bec3bf 100644
--- a/fs/kernfs/ve.c
+++ b/fs/kernfs/ve.c
@@ -64,11 +64,15 @@ int kernfs_ve_permission(struct kernfs_node *kn,
                return 0;
 
        /* Entries with namespace tag and their sub-entries always visible */
+       rcu_read_lock();
        while (tmp_kn) {
-               if (tmp_kn->ns)
+               if (tmp_kn->ns) {
+                       rcu_read_unlock();
                        return 0;
+               }
                tmp_kn = kernfs_parent(tmp_kn);
        }
+       rcu_read_unlock();
 
        if (kernfs_type(kn) == KERNFS_LINK)
                kn = kn->symlink.target_kn;
@@ -108,11 +112,15 @@ bool kernfs_d_visible(struct kernfs_node *kn, struct 
kernfs_super_info *info)
                return true;
 
        /* Entries with namespace tag and their sub-entries always visible */
+       rcu_read_lock();
        while (tmp_kn) {
-               if (tmp_kn->ns)
+               if (tmp_kn->ns) {
+                       rcu_read_unlock();
                        return true;
+               }
                tmp_kn = kernfs_parent(tmp_kn);
        }
+       rcu_read_unlock();
 
        /* Symlinks are visible if target kn is visible */
        if (kernfs_type(kn) == KERNFS_LINK)
-- 
2.47.1

_______________________________________________
Devel mailing list
[email protected]
https://lists.openvz.org/mailman/listinfo/devel

Reply via email to