fs: fix dropping of rcu-walk from force_reval_path
As J. R. Okajima noted, force_reval_path passes in the same dentry to
d_revalidate as the one in the nameidata structure (other callers pass in a
child), so the locking breaks. This can oops with a chrooted nfs mount, for
example. Similarly there can be other problems with revalidating a dentry
which is already in nameidata of the path walk.
Signed-off-by: Nick Piggin <npiggin@kernel.dk>
diff --git a/fs/namei.c b/fs/namei.c
index 0f02359..14c73ed 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -479,6 +479,14 @@
struct fs_struct *fs = current->fs;
struct dentry *parent = nd->path.dentry;
+ /*
+ * It can be possible to revalidate the dentry that we started
+ * the path walk with. force_reval_path may also revalidate the
+ * dentry already committed to the nameidata.
+ */
+ if (unlikely(parent == dentry))
+ return nameidata_drop_rcu(nd);
+
BUG_ON(!(nd->flags & LOOKUP_RCU));
if (nd->root.mnt) {
spin_lock(&fs->lock);