fs: don't scan the inode cache before SB_BORN is set
authorDave Chinner <dchinner@redhat.com>
Fri, 11 May 2018 01:20:57 +0000 (11:20 +1000)
committerAl Viro <viro@zeniv.linux.org.uk>
Fri, 11 May 2018 19:37:57 +0000 (15:37 -0400)
We recently had an oops reported on a 4.14 kernel in
xfs_reclaim_inodes_count() where sb->s_fs_info pointed to garbage
and so the m_perag_tree lookup walked into lala land.  It produces
an oops down this path during the failed mount:


The problem is that the superblock shrinker is running before the
filesystem structures it depends on have been fully set up. i.e.
the shrinker is registered in sget(), before ->fill_super() has been
called, and the shrinker can call into the filesystem before
fill_super() does it's setup work. Essentially we are exposed to
both use-after-free and use-before-initialisation bugs here.

To fix this, add a check for the SB_BORN flag in super_cache_count.
In general, this flag is not set until ->fs_mount() completes
successfully, so we know that it is set after the filesystem
setup has completed. This matches the trylock_super() behaviour
which will not let super_cache_scan() run if SB_BORN is not set, and
hence will not allow the superblock shrinker from entering the
filesystem while it is being set up or after it has failed setup
and is being torn down.

Cc: stable@kernel.org
Signed-Off-By: Dave Chinner <dchinner@redhat.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>

index 122c402049a25b29c5ed1e9aa0ef6ace1f657e6c..4b5b562176d074fe924329da795661650369b831 100644 (file)
@@ -121,13 +121,23 @@ static unsigned long super_cache_count(struct shrinker *shrink,
        sb = container_of(shrink, struct super_block, s_shrink);
-        * Don't call trylock_super as it is a potential
-        * scalability bottleneck. The counts could get updated
-        * between super_cache_count and super_cache_scan anyway.
-        * Call to super_cache_count with shrinker_rwsem held
-        * ensures the safety of call to list_lru_shrink_count() and
-        * s_op->nr_cached_objects().
+        * We don't call trylock_super() here as it is a scalability bottleneck,
+        * so we're exposed to partial setup state. The shrinker rwsem does not
+        * protect filesystem operations backing list_lru_shrink_count() or
+        * s_op->nr_cached_objects(). Counts can change between
+        * super_cache_count and super_cache_scan, so we really don't need locks
+        * here.
+        *
+        * However, if we are currently mounting the superblock, the underlying
+        * filesystem might be in a state of partial construction and hence it
+        * is dangerous to access it.  trylock_super() uses a SB_BORN check to
+        * avoid this situation, so do the same here. The memory barrier is
+        * matched with the one in mount_fs() as we don't hold locks here.
+       if (!(sb->s_flags & SB_BORN))
+               return 0;
+       smp_rmb();
        if (sb->s_op && sb->s_op->nr_cached_objects)
                total_objects = sb->s_op->nr_cached_objects(sb, sc);
@@ -1272,6 +1282,14 @@ mount_fs(struct file_system_type *type, int flags, const char *name, void *data)
        sb = root->d_sb;
+       /*
+        * Write barrier is for super_cache_count(). We place it before setting
+        * SB_BORN as the data dependency between the two functions is the
+        * superblock structure contents that we just set up, not the SB_BORN
+        * flag.
+        */
+       smp_wmb();
        sb->s_flags |= SB_BORN;
        error = security_sb_kern_mount(sb, flags, secdata);