do_umount(): add missing barrier before refcount checks in sync case
authorAl Viro <viro@zeniv.linux.org.uk>
Tue, 29 Apr 2025 03:56:14 +0000 (23:56 -0400)
committerAl Viro <viro@zeniv.linux.org.uk>
Fri, 9 May 2025 22:05:55 +0000 (18:05 -0400)
do_umount() analogue of the race fixed in 119e1ef80ecf "fix
__legitimize_mnt()/mntput() race".  Here we want to make sure that
if __legitimize_mnt() doesn't notice our lock_mount_hash(), we will
notice their refcount increment.  Harder to hit than mntput_no_expire()
one, fortunately, and consequences are milder (sync umount acting
like umount -l on a rare race with RCU pathwalk hitting at just the
wrong time instead of use-after-free galore mntput_no_expire()
counterpart used to be hit).  Still a bug...

Fixes: 48a066e72d97 ("RCU'd vfsmounts")
Reviewed-by: Christian Brauner <brauner@kernel.org>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
fs/namespace.c

index eba4748388b1d002dbe91ed651948c7554123701..d8a344d0a80aabb0f2c8cabb17fa3eff2c6a913b 100644 (file)
@@ -787,7 +787,7 @@ int __legitimize_mnt(struct vfsmount *bastard, unsigned seq)
                return 0;
        mnt = real_mount(bastard);
        mnt_add_count(mnt, 1);
-       smp_mb();                       // see mntput_no_expire()
+       smp_mb();               // see mntput_no_expire() and do_umount()
        if (likely(!read_seqretry(&mount_lock, seq)))
                return 0;
        lock_mount_hash();
@@ -2044,6 +2044,7 @@ static int do_umount(struct mount *mnt, int flags)
                        umount_tree(mnt, UMOUNT_PROPAGATE);
                retval = 0;
        } else {
+               smp_mb(); // paired with __legitimize_mnt()
                shrink_submounts(mnt);
                retval = -EBUSY;
                if (!propagate_mount_busy(mnt, 2)) {