Unverified Commit 998541db authored by Christian Brauner's avatar Christian Brauner
Browse files

Merge patch series "vfs: if RESOLVE_NO_XDEV passed to openat2, don't *trigger* automounts"

Askar Safin <safinaskar@zohomail.com> says:

openat2 had a bug: if we pass RESOLVE_NO_XDEV, then openat2
doesn't traverse through automounts, but may still trigger them.
See this link for full bug report with reproducer:
https://lore.kernel.org/linux-fsdevel/20250817075252.4137628-1-safinaskar@zohomail.com/

This patchset fixes the bug.

RESOLVE_NO_XDEV logic hopefully becomes more clear:
now we immediately fail when we cross mountpoints.

* patches from https://lore.kernel.org/20250825181233.2464822-1-safinaskar@zohomail.com:
  openat2: don't trigger automounts with RESOLVE_NO_XDEV
  namei: move cross-device check to __traverse_mounts
  namei: remove LOOKUP_NO_XDEV check from handle_mounts
  namei: move cross-device check to traverse_mounts

Link: https://lore.kernel.org/20250825181233.2464822-1-safinaskar@zohomail.com


Signed-off-by: default avatarChristian Brauner <brauner@kernel.org>
parents 7f9d34b0 042a6068
Loading
Loading
Loading
Loading
+14 −6
Original line number Diff line number Diff line
@@ -1449,6 +1449,10 @@ static int follow_automount(struct path *path, int *count, unsigned lookup_flags
	    dentry->d_inode)
		return -EISDIR;

	/* No need to trigger automounts if mountpoint crossing is disabled. */
	if (lookup_flags & LOOKUP_NO_XDEV)
		return -EXDEV;

	if (count && (*count)++ >= MAXSYMLINKS)
		return -ELOOP;

@@ -1472,6 +1476,10 @@ static int __traverse_mounts(struct path *path, unsigned flags, bool *jumped,
		/* Allow the filesystem to manage the transit without i_rwsem
		 * being held. */
		if (flags & DCACHE_MANAGE_TRANSIT) {
			if (lookup_flags & LOOKUP_NO_XDEV) {
				ret = -EXDEV;
				break;
			}
			ret = path->dentry->d_op->d_manage(path, false);
			flags = smp_load_acquire(&path->dentry->d_flags);
			if (ret < 0)
@@ -1489,6 +1497,10 @@ static int __traverse_mounts(struct path *path, unsigned flags, bool *jumped,
				// here we know it's positive
				flags = path->dentry->d_flags;
				need_mntput = true;
				if (unlikely(lookup_flags & LOOKUP_NO_XDEV)) {
					ret = -EXDEV;
					break;
				}
				continue;
			}
		}
@@ -1630,12 +1642,8 @@ static inline int handle_mounts(struct nameidata *nd, struct dentry *dentry,
			return -ECHILD;
	}
	ret = traverse_mounts(path, &jumped, &nd->total_link_count, nd->flags);
	if (jumped) {
		if (unlikely(nd->flags & LOOKUP_NO_XDEV))
			ret = -EXDEV;
		else
	if (jumped)
		nd->state |= ND_JUMPED;
	}
	if (unlikely(ret)) {
		dput(path->dentry);
		if (path->mnt != nd->path.mnt)