]> git.baikalelectronics.ru Git - kernel.git/commitdiff
__follow_mount_rcu(): verify that mount_lock remains unchanged
authorAl Viro <viro@zeniv.linux.org.uk>
Mon, 4 Jul 2022 21:26:29 +0000 (17:26 -0400)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 17 Aug 2022 12:24:19 +0000 (14:24 +0200)
commit bcbb7f77b7e083544c7fca95551a4c6c36d7a47d upstream.

Validate mount_lock seqcount as soon as we cross into mount in RCU
mode.  Sure, ->mnt_root is pinned and will remain so until we
do rcu_read_unlock() anyway, and we will eventually fail to unlazy if
the mount_lock had been touched, but we might run into a hard error
(e.g. -ENOENT) before trying to unlazy.  And it's possible to end
up with RCU pathwalk racing with rename() and umount() in a way
that would fail with -ENOENT while non-RCU pathwalk would've
succeeded with any timings.

Once upon a time we hadn't needed that, but analysis had been subtle,
brittle and went out of window as soon as RENAME_EXCHANGE had been
added.

It's narrow, hard to hit and won't get you anything other than
stray -ENOENT that could be arranged in much easier way with the
same priveleges, but it's a bug all the same.

Cc: stable@kernel.org
X-sky-is-falling: unlikely
Fixes: e38dd2e5c293 "vfs: add cross-rename"
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
fs/namei.c

index 66e0fe262a898120342456b64f64c10509ce7045..1fd854d4cd2c081d4f70070be77ceb24881275bf 100644 (file)
@@ -1461,6 +1461,8 @@ static bool __follow_mount_rcu(struct nameidata *nd, struct path *path,
                                 * becoming unpinned.
                                 */
                                flags = dentry->d_flags;
+                               if (read_seqretry(&mount_lock, nd->m_seq))
+                                       return false;
                                continue;
                        }
                        if (read_seqretry(&mount_lock, nd->m_seq))