From: Al Viro Date: Mon, 4 Jul 2022 21:26:29 +0000 (-0400) Subject: __follow_mount_rcu(): verify that mount_lock remains unchanged X-Git-Tag: baikal/mips/sdk6.1~5168^2~9 X-Git-Url: https://git.baikalelectronics.ru/sdk/?a=commitdiff_plain;h=bcbb7f77b7e083544c7fca95551a4c6c36d7a47d;p=kernel.git __follow_mount_rcu(): verify that mount_lock remains unchanged 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 --- diff --git a/fs/namei.c b/fs/namei.c index 1f28d3f463c3b..4dbf55b37ec63 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -1505,6 +1505,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))