linux-fsdevel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/4] vfs: if RESOLVE_NO_XDEV passed to openat2, don't *trigger* automounts
@ 2025-08-17 17:15 Askar Safin
  2025-08-17 17:15 ` [PATCH 1/4] vfs: fs/namei.c: move cross-device check to traverse_mounts Askar Safin
                   ` (5 more replies)
  0 siblings, 6 replies; 17+ messages in thread
From: Askar Safin @ 2025-08-17 17:15 UTC (permalink / raw)
  To: Alexander Viro, Christian Brauner, Jan Kara, cyphar, Ian Kent
  Cc: linux-fsdevel, David Howells, autofs mailing list, patches

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.

I think this patchset should get to -fixes and stable trees.

I split everything to very small commits to make
everything as bisectable as possible.

Minimal testing was performed. I tested that my original
reproducer doesn't reproduce anymore. And I did boot-test
with localmodconfig in qemu

I'm not very attached to this patchset. I. e. I will not be offended
if someone else will submit different fix for this bug.

Askar Safin (4):
  vfs: fs/namei.c: move cross-device check to traverse_mounts
  vfs: fs/namei.c: remove LOOKUP_NO_XDEV check from handle_mounts
  vfs: fs/namei.c: move cross-device check to __traverse_mounts
  vfs: fs/namei.c: if RESOLVE_NO_XDEV passed to openat2, don't *trigger*
    automounts

 fs/namei.c | 29 +++++++++++++++++++++++------
 1 file changed, 23 insertions(+), 6 deletions(-)

-- 
2.47.2


^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH 1/4] vfs: fs/namei.c: move cross-device check to traverse_mounts
  2025-08-17 17:15 [PATCH 0/4] vfs: if RESOLVE_NO_XDEV passed to openat2, don't *trigger* automounts Askar Safin
@ 2025-08-17 17:15 ` Askar Safin
  2025-08-17 17:15 ` [PATCH 2/4] vfs: fs/namei.c: remove LOOKUP_NO_XDEV check from handle_mounts Askar Safin
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 17+ messages in thread
From: Askar Safin @ 2025-08-17 17:15 UTC (permalink / raw)
  To: Alexander Viro, Christian Brauner, Jan Kara, cyphar, Ian Kent
  Cc: linux-fsdevel, David Howells, autofs mailing list, patches

This is preparation to RESOLVE_NO_XDEV fix in following commits.
No functional change intended

Signed-off-by: Askar Safin <safinaskar@zohomail.com>
---
 fs/namei.c | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/fs/namei.c b/fs/namei.c
index cd43ff89fbaa..1e13d8e119a4 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -1518,6 +1518,7 @@ static inline int traverse_mounts(struct path *path, bool *jumped,
 				  int *count, unsigned lookup_flags)
 {
 	unsigned flags = smp_load_acquire(&path->dentry->d_flags);
+	int ret;
 
 	/* fastpath */
 	if (likely(!(flags & DCACHE_MANAGED_DENTRY))) {
@@ -1526,7 +1527,11 @@ static inline int traverse_mounts(struct path *path, bool *jumped,
 			return -ENOENT;
 		return 0;
 	}
-	return __traverse_mounts(path, flags, jumped, count, lookup_flags);
+
+	ret = __traverse_mounts(path, flags, jumped, count, lookup_flags);
+	if (*jumped && unlikely(lookup_flags & LOOKUP_NO_XDEV))
+		return -EXDEV;
+	return ret;
 }
 
 int follow_down_one(struct path *path)
@@ -1631,9 +1636,7 @@ static inline int handle_mounts(struct nameidata *nd, struct dentry *dentry,
 	}
 	ret = traverse_mounts(path, &jumped, &nd->total_link_count, nd->flags);
 	if (jumped) {
-		if (unlikely(nd->flags & LOOKUP_NO_XDEV))
-			ret = -EXDEV;
-		else
+		if (!unlikely(nd->flags & LOOKUP_NO_XDEV))
 			nd->state |= ND_JUMPED;
 	}
 	if (unlikely(ret)) {
-- 
2.47.2


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH 2/4] vfs: fs/namei.c: remove LOOKUP_NO_XDEV check from handle_mounts
  2025-08-17 17:15 [PATCH 0/4] vfs: if RESOLVE_NO_XDEV passed to openat2, don't *trigger* automounts Askar Safin
  2025-08-17 17:15 ` [PATCH 1/4] vfs: fs/namei.c: move cross-device check to traverse_mounts Askar Safin
@ 2025-08-17 17:15 ` Askar Safin
  2025-08-17 18:00   ` Al Viro
  2025-08-17 17:15 ` [PATCH 3/4] vfs: fs/namei.c: move cross-device check to __traverse_mounts Askar Safin
                   ` (3 subsequent siblings)
  5 siblings, 1 reply; 17+ messages in thread
From: Askar Safin @ 2025-08-17 17:15 UTC (permalink / raw)
  To: Alexander Viro, Christian Brauner, Jan Kara, cyphar, Ian Kent
  Cc: linux-fsdevel, David Howells, autofs mailing list, patches

This is preparation to RESOLVE_NO_XDEV fix in following commits.
No functional change intended

Signed-off-by: Askar Safin <safinaskar@zohomail.com>
---
 fs/namei.c | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/fs/namei.c b/fs/namei.c
index 1e13d8e119a4..00f79559e135 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -1635,10 +1635,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))
-			nd->state |= ND_JUMPED;
-	}
+	if (jumped)
+		nd->state |= ND_JUMPED;
 	if (unlikely(ret)) {
 		dput(path->dentry);
 		if (path->mnt != nd->path.mnt)
-- 
2.47.2


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH 3/4] vfs: fs/namei.c: move cross-device check to __traverse_mounts
  2025-08-17 17:15 [PATCH 0/4] vfs: if RESOLVE_NO_XDEV passed to openat2, don't *trigger* automounts Askar Safin
  2025-08-17 17:15 ` [PATCH 1/4] vfs: fs/namei.c: move cross-device check to traverse_mounts Askar Safin
  2025-08-17 17:15 ` [PATCH 2/4] vfs: fs/namei.c: remove LOOKUP_NO_XDEV check from handle_mounts Askar Safin
@ 2025-08-17 17:15 ` Askar Safin
  2025-08-17 17:15 ` [PATCH 4/4] vfs: fs/namei.c: if RESOLVE_NO_XDEV passed to openat2, don't *trigger* automounts Askar Safin
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 17+ messages in thread
From: Askar Safin @ 2025-08-17 17:15 UTC (permalink / raw)
  To: Alexander Viro, Christian Brauner, Jan Kara, cyphar, Ian Kent
  Cc: linux-fsdevel, David Howells, autofs mailing list, patches

This is preparation to RESOLVE_NO_XDEV fix in following commits.
Also this commit makes LOOKUP_NO_XDEV logic more clear: now we
immediately fail with EXDEV on first mount crossing
instead of waiting for very end.

No functional change intended

Signed-off-by: Askar Safin <safinaskar@zohomail.com>
---
 fs/namei.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/fs/namei.c b/fs/namei.c
index 00f79559e135..6f43f96f506d 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -1489,6 +1489,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;
 			}
 		}
@@ -1518,7 +1522,6 @@ static inline int traverse_mounts(struct path *path, bool *jumped,
 				  int *count, unsigned lookup_flags)
 {
 	unsigned flags = smp_load_acquire(&path->dentry->d_flags);
-	int ret;
 
 	/* fastpath */
 	if (likely(!(flags & DCACHE_MANAGED_DENTRY))) {
@@ -1528,10 +1531,7 @@ static inline int traverse_mounts(struct path *path, bool *jumped,
 		return 0;
 	}
 
-	ret = __traverse_mounts(path, flags, jumped, count, lookup_flags);
-	if (*jumped && unlikely(lookup_flags & LOOKUP_NO_XDEV))
-		return -EXDEV;
-	return ret;
+	return __traverse_mounts(path, flags, jumped, count, lookup_flags);
 }
 
 int follow_down_one(struct path *path)
-- 
2.47.2


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH 4/4] vfs: fs/namei.c: if RESOLVE_NO_XDEV passed to openat2, don't *trigger* automounts
  2025-08-17 17:15 [PATCH 0/4] vfs: if RESOLVE_NO_XDEV passed to openat2, don't *trigger* automounts Askar Safin
                   ` (2 preceding siblings ...)
  2025-08-17 17:15 ` [PATCH 3/4] vfs: fs/namei.c: move cross-device check to __traverse_mounts Askar Safin
@ 2025-08-17 17:15 ` Askar Safin
  2025-08-17 17:53   ` Al Viro
  2025-08-18  5:17   ` Aleksa Sarai
  2025-08-18  5:31 ` [PATCH 0/4] vfs: " Aleksa Sarai
  2025-08-19  8:24 ` Christian Brauner
  5 siblings, 2 replies; 17+ messages in thread
From: Askar Safin @ 2025-08-17 17:15 UTC (permalink / raw)
  To: Alexander Viro, Christian Brauner, Jan Kara, cyphar, Ian Kent
  Cc: linux-fsdevel, David Howells, autofs mailing list, patches

openat2 had a bug: if we pass RESOLVE_NO_XDEV, then openat2
doesn't traverse through automounts, but may still trigger them.
(See the link for full bug report with reproducer.)

This commit fixes this bug.

Link: https://lore.kernel.org/linux-fsdevel/20250817075252.4137628-1-safinaskar@zohomail.com/
Fixes: fddb5d430ad9fa91b49b1 ("open: introduce openat2(2) syscall")
Signed-off-by: Askar Safin <safinaskar@zohomail.com>
---
 fs/namei.c | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/fs/namei.c b/fs/namei.c
index 6f43f96f506d..55e2447699a4 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -1449,6 +1449,18 @@ static int follow_automount(struct path *path, int *count, unsigned lookup_flags
 	    dentry->d_inode)
 		return -EISDIR;
 
+	/* "if" above returned -EISDIR if we want to get automount point itself
+	 * as opposed to new mount. Getting automount point itself is, of course,
+	 * totally okay even if we have LOOKUP_NO_XDEV.
+	 *
+	 * But if we got here, then we want to get
+	 * new mount. Let's deny this if LOOKUP_NO_XDEV is specified.
+	 * If we have LOOKUP_NO_XDEV, then we want to deny not only
+	 * traversing through automounts, but also triggering them
+	 */
+	if (lookup_flags & LOOKUP_NO_XDEV)
+		return -EXDEV;
+
 	if (count && (*count)++ >= MAXSYMLINKS)
 		return -ELOOP;
 
@@ -1472,6 +1484,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)
-- 
2.47.2


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* Re: [PATCH 4/4] vfs: fs/namei.c: if RESOLVE_NO_XDEV passed to openat2, don't *trigger* automounts
  2025-08-17 17:15 ` [PATCH 4/4] vfs: fs/namei.c: if RESOLVE_NO_XDEV passed to openat2, don't *trigger* automounts Askar Safin
@ 2025-08-17 17:53   ` Al Viro
  2025-08-17 17:54     ` Al Viro
  2025-08-18  5:17   ` Aleksa Sarai
  1 sibling, 1 reply; 17+ messages in thread
From: Al Viro @ 2025-08-17 17:53 UTC (permalink / raw)
  To: Askar Safin
  Cc: Christian Brauner, Jan Kara, cyphar, Ian Kent, linux-fsdevel,
	David Howells, autofs mailing list, patches

On Sun, Aug 17, 2025 at 05:15:13PM +0000, Askar Safin wrote:

> @@ -1472,6 +1484,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;

I don't thing it's right in RCU mode, if nothing else...

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH 4/4] vfs: fs/namei.c: if RESOLVE_NO_XDEV passed to openat2, don't *trigger* automounts
  2025-08-17 17:53   ` Al Viro
@ 2025-08-17 17:54     ` Al Viro
  0 siblings, 0 replies; 17+ messages in thread
From: Al Viro @ 2025-08-17 17:54 UTC (permalink / raw)
  To: Askar Safin
  Cc: Christian Brauner, Jan Kara, cyphar, Ian Kent, linux-fsdevel,
	David Howells, autofs mailing list, patches

On Sun, Aug 17, 2025 at 06:53:19PM +0100, Al Viro wrote:
> On Sun, Aug 17, 2025 at 05:15:13PM +0000, Askar Safin wrote:
> 
> > @@ -1472,6 +1484,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;
> 
> I don't thing it's right in RCU mode, if nothing else...

Nevermind, that's a non-RCU path.

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH 2/4] vfs: fs/namei.c: remove LOOKUP_NO_XDEV check from handle_mounts
  2025-08-17 17:15 ` [PATCH 2/4] vfs: fs/namei.c: remove LOOKUP_NO_XDEV check from handle_mounts Askar Safin
@ 2025-08-17 18:00   ` Al Viro
  0 siblings, 0 replies; 17+ messages in thread
From: Al Viro @ 2025-08-17 18:00 UTC (permalink / raw)
  To: Askar Safin
  Cc: Christian Brauner, Jan Kara, cyphar, Ian Kent, linux-fsdevel,
	David Howells, autofs mailing list, patches

On Sun, Aug 17, 2025 at 05:15:11PM +0000, Askar Safin wrote:
> This is preparation to RESOLVE_NO_XDEV fix in following commits.
> No functional change intended
> 
> Signed-off-by: Askar Safin <safinaskar@zohomail.com>
> ---
>  fs/namei.c | 6 ++----
>  1 file changed, 2 insertions(+), 4 deletions(-)
> 
> diff --git a/fs/namei.c b/fs/namei.c
> index 1e13d8e119a4..00f79559e135 100644
> --- a/fs/namei.c
> +++ b/fs/namei.c
> @@ -1635,10 +1635,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))
> -			nd->state |= ND_JUMPED;
> -	}
> +	if (jumped)
> +		nd->state |= ND_JUMPED;

I'd add something along the lines of "the only place that ever looks at
ND_JUMPED in nd->state is complete_walk() and we are not going to reach
it if handle_mounts() returns an error" to commit message.

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH 4/4] vfs: fs/namei.c: if RESOLVE_NO_XDEV passed to openat2, don't *trigger* automounts
  2025-08-17 17:15 ` [PATCH 4/4] vfs: fs/namei.c: if RESOLVE_NO_XDEV passed to openat2, don't *trigger* automounts Askar Safin
  2025-08-17 17:53   ` Al Viro
@ 2025-08-18  5:17   ` Aleksa Sarai
  2025-08-18  7:15     ` Aleksa Sarai
  1 sibling, 1 reply; 17+ messages in thread
From: Aleksa Sarai @ 2025-08-18  5:17 UTC (permalink / raw)
  To: Askar Safin
  Cc: Alexander Viro, Christian Brauner, Jan Kara, Ian Kent,
	linux-fsdevel, David Howells, autofs mailing list, patches

[-- Attachment #1: Type: text/plain, Size: 2496 bytes --]

On 2025-08-17, Askar Safin <safinaskar@zohomail.com> wrote:
> openat2 had a bug: if we pass RESOLVE_NO_XDEV, then openat2
> doesn't traverse through automounts, but may still trigger them.
> (See the link for full bug report with reproducer.)
> 
> This commit fixes this bug.
> 
> Link: https://lore.kernel.org/linux-fsdevel/20250817075252.4137628-1-safinaskar@zohomail.com/
> Fixes: fddb5d430ad9fa91b49b1 ("open: introduce openat2(2) syscall")
> Signed-off-by: Askar Safin <safinaskar@zohomail.com>

Reviewed-by: Aleksa Sarai <cyphar@cyphar.com>

> ---
>  fs/namei.c | 16 ++++++++++++++++
>  1 file changed, 16 insertions(+)
> 
> diff --git a/fs/namei.c b/fs/namei.c
> index 6f43f96f506d..55e2447699a4 100644
> --- a/fs/namei.c
> +++ b/fs/namei.c
> @@ -1449,6 +1449,18 @@ static int follow_automount(struct path *path, int *count, unsigned lookup_flags
>  	    dentry->d_inode)
>  		return -EISDIR;
>  
> +	/* "if" above returned -EISDIR if we want to get automount point itself
> +	 * as opposed to new mount. Getting automount point itself is, of course,
> +	 * totally okay even if we have LOOKUP_NO_XDEV.
> +	 *
> +	 * But if we got here, then we want to get
> +	 * new mount. Let's deny this if LOOKUP_NO_XDEV is specified.
> +	 * If we have LOOKUP_NO_XDEV, then we want to deny not only
> +	 * traversing through automounts, but also triggering them
> +	 */

This comment really could be one sentence:

  /* No need to trigger automounts if mountpoint crossing is disabled. */

Or if you really want to mention -EISDIR, then:

  /*
   * No need to trigger automounts if mountpoint crossing is disabled.
   * If the caller is trying to check the autmount point itself, -EISDIR
   * above handles that case for us.
   */

> +	if (lookup_flags & LOOKUP_NO_XDEV)
> +		return -EXDEV;
> +
>  	if (count && (*count)++ >= MAXSYMLINKS)
>  		return -ELOOP;
>  
> @@ -1472,6 +1484,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)
> -- 
> 2.47.2
> 

-- 
Aleksa Sarai
Senior Software Engineer (Containers)
SUSE Linux GmbH
https://www.cyphar.com/

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 265 bytes --]

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH 0/4] vfs: if RESOLVE_NO_XDEV passed to openat2, don't *trigger* automounts
  2025-08-17 17:15 [PATCH 0/4] vfs: if RESOLVE_NO_XDEV passed to openat2, don't *trigger* automounts Askar Safin
                   ` (3 preceding siblings ...)
  2025-08-17 17:15 ` [PATCH 4/4] vfs: fs/namei.c: if RESOLVE_NO_XDEV passed to openat2, don't *trigger* automounts Askar Safin
@ 2025-08-18  5:31 ` Aleksa Sarai
  2025-08-19  8:21   ` Christian Brauner
  2025-08-19  8:24 ` Christian Brauner
  5 siblings, 1 reply; 17+ messages in thread
From: Aleksa Sarai @ 2025-08-18  5:31 UTC (permalink / raw)
  To: Askar Safin
  Cc: Alexander Viro, Christian Brauner, Jan Kara, Ian Kent,
	linux-fsdevel, David Howells, autofs mailing list, patches

[-- Attachment #1: Type: text/plain, Size: 2384 bytes --]

On 2025-08-17, Askar Safin <safinaskar@zohomail.com> wrote:
> 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.
> 
> I think this patchset should get to -fixes and stable trees.

You need to add

  Cc: <stable@vger.kernel.org> # v5.2+

(along with a Fixes: ... tag) for each commit you would like to be
backported.

> I split everything to very small commits to make
> everything as bisectable as possible.

I would merge the first three patches -- adding and removing code like
that is a little unnecessary. I also don't think you need those patches
to be backported, right? (Especially since they are touching stuff that
Al has reworked a few times since openat2 was merged back in Linux 5.2.)

I only think the last one needs to be in stable.

> Minimal testing was performed. I tested that my original
> reproducer doesn't reproduce anymore. And I did boot-test
> with localmodconfig in qemu
> 
> I'm not very attached to this patchset. I. e. I will not be offended
> if someone else will submit different fix for this bug.
> 
> Askar Safin (4):
>   vfs: fs/namei.c: move cross-device check to traverse_mounts
>   vfs: fs/namei.c: remove LOOKUP_NO_XDEV check from handle_mounts
>   vfs: fs/namei.c: move cross-device check to __traverse_mounts

This is a minor nit, but could you use something like "namei: ..." (or
"fs: namei: ...") as a prefix for commit subjects? If you merge them
all, something like:

  namei: move LOOKUP_NO_XDEV checks to __traverse_mounts

would be fine.

>   vfs: fs/namei.c: if RESOLVE_NO_XDEV passed to openat2, don't *trigger*
>     automounts

and this one should read a bit clearer with

  openat2: don't trigger automounts with RESOLVE_NO_XDEV

or if you prefer

  namei: don't trigger automounts with LOOKUP_NO_XDEV

>  fs/namei.c | 29 +++++++++++++++++++++++------
>  1 file changed, 23 insertions(+), 6 deletions(-)

-- 
Aleksa Sarai
Senior Software Engineer (Containers)
SUSE Linux GmbH
https://www.cyphar.com/

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 265 bytes --]

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH 4/4] vfs: fs/namei.c: if RESOLVE_NO_XDEV passed to openat2, don't *trigger* automounts
  2025-08-18  5:17   ` Aleksa Sarai
@ 2025-08-18  7:15     ` Aleksa Sarai
  2025-08-25 17:48       ` Askar Safin
  0 siblings, 1 reply; 17+ messages in thread
From: Aleksa Sarai @ 2025-08-18  7:15 UTC (permalink / raw)
  To: Askar Safin
  Cc: Alexander Viro, Christian Brauner, Jan Kara, Ian Kent,
	linux-fsdevel, David Howells, autofs mailing list, patches

[-- Attachment #1: Type: text/plain, Size: 3380 bytes --]

On 2025-08-18, Aleksa Sarai <cyphar@cyphar.com> wrote:
> On 2025-08-17, Askar Safin <safinaskar@zohomail.com> wrote:
> > openat2 had a bug: if we pass RESOLVE_NO_XDEV, then openat2
> > doesn't traverse through automounts, but may still trigger them.
> > (See the link for full bug report with reproducer.)
> > 
> > This commit fixes this bug.
> > 
> > Link: https://lore.kernel.org/linux-fsdevel/20250817075252.4137628-1-safinaskar@zohomail.com/
> > Fixes: fddb5d430ad9fa91b49b1 ("open: introduce openat2(2) syscall")
> > Signed-off-by: Askar Safin <safinaskar@zohomail.com>
> 
> Reviewed-by: Aleksa Sarai <cyphar@cyphar.com>
> 
> > ---
> >  fs/namei.c | 16 ++++++++++++++++
> >  1 file changed, 16 insertions(+)
> > 
> > diff --git a/fs/namei.c b/fs/namei.c
> > index 6f43f96f506d..55e2447699a4 100644
> > --- a/fs/namei.c
> > +++ b/fs/namei.c
> > @@ -1449,6 +1449,18 @@ static int follow_automount(struct path *path, int *count, unsigned lookup_flags
> >  	    dentry->d_inode)
> >  		return -EISDIR;
> >  
> > +	/* "if" above returned -EISDIR if we want to get automount point itself
> > +	 * as opposed to new mount. Getting automount point itself is, of course,
> > +	 * totally okay even if we have LOOKUP_NO_XDEV.
> > +	 *
> > +	 * But if we got here, then we want to get
> > +	 * new mount. Let's deny this if LOOKUP_NO_XDEV is specified.
> > +	 * If we have LOOKUP_NO_XDEV, then we want to deny not only
> > +	 * traversing through automounts, but also triggering them
> > +	 */
> 
> This comment really could be one sentence:
> 
>   /* No need to trigger automounts if mountpoint crossing is disabled. */
> 
> Or if you really want to mention -EISDIR, then:
> 
>   /*
>    * No need to trigger automounts if mountpoint crossing is disabled.
>    * If the caller is trying to check the autmount point itself, -EISDIR
>    * above handles that case for us.
>    */

That being said, the only user of LOOKUP_NO_XDEV is openat2(), so the
stat stuff is a bit of a red herring.

At the moment, O_PATH and O_PATH|O_DIRECTORY have different behaviours
here, and I'm not sure users expect that -- O_PATH will let you get a
handle to the automount point, but O_DIRECTORY causes the -EISDIR case
to be skipped and triggers the automount. We can't just remove
LOOKUP_DIRECTORY from the check since it is used for a lot of
kernel-internal lookups, but we should have O_PATH|O_DIRECTORY produce
identical behaviour to O_PATH in this case IMHO.

> > +	if (lookup_flags & LOOKUP_NO_XDEV)
> > +		return -EXDEV;
> > +
> >  	if (count && (*count)++ >= MAXSYMLINKS)
> >  		return -ELOOP;
> >  
> > @@ -1472,6 +1484,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)
> > -- 
> > 2.47.2
> > 
> 
> -- 
> Aleksa Sarai
> Senior Software Engineer (Containers)
> SUSE Linux GmbH
> https://www.cyphar.com/



-- 
Aleksa Sarai
Senior Software Engineer (Containers)
SUSE Linux GmbH
https://www.cyphar.com/

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 265 bytes --]

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH 0/4] vfs: if RESOLVE_NO_XDEV passed to openat2, don't *trigger* automounts
  2025-08-18  5:31 ` [PATCH 0/4] vfs: " Aleksa Sarai
@ 2025-08-19  8:21   ` Christian Brauner
  2025-08-25 12:46     ` Askar Safin
  0 siblings, 1 reply; 17+ messages in thread
From: Christian Brauner @ 2025-08-19  8:21 UTC (permalink / raw)
  To: Aleksa Sarai
  Cc: Askar Safin, Alexander Viro, Jan Kara, Ian Kent, linux-fsdevel,
	David Howells, autofs mailing list, patches

On Mon, Aug 18, 2025 at 03:31:27PM +1000, Aleksa Sarai wrote:
> On 2025-08-17, Askar Safin <safinaskar@zohomail.com> wrote:
> > 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.
> > 
> > I think this patchset should get to -fixes and stable trees.
> 
> You need to add
> 
>   Cc: <stable@vger.kernel.org> # v5.2+
> 
> (along with a Fixes: ... tag) for each commit you would like to be
> backported.
> 
> > I split everything to very small commits to make
> > everything as bisectable as possible.
> 
> I would merge the first three patches -- adding and removing code like

Agreed.

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH 0/4] vfs: if RESOLVE_NO_XDEV passed to openat2, don't *trigger* automounts
  2025-08-17 17:15 [PATCH 0/4] vfs: if RESOLVE_NO_XDEV passed to openat2, don't *trigger* automounts Askar Safin
                   ` (4 preceding siblings ...)
  2025-08-18  5:31 ` [PATCH 0/4] vfs: " Aleksa Sarai
@ 2025-08-19  8:24 ` Christian Brauner
  2025-08-20 18:04   ` Askar Safin
  5 siblings, 1 reply; 17+ messages in thread
From: Christian Brauner @ 2025-08-19  8:24 UTC (permalink / raw)
  To: Askar Safin
  Cc: Alexander Viro, Jan Kara, cyphar, Ian Kent, linux-fsdevel,
	David Howells, autofs mailing list, patches

On Sun, Aug 17, 2025 at 05:15:09PM +0000, Askar Safin wrote:
> 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.

Thanks, this looks all sane. Once you've addressed all comments I'll get
this into -next.

> RESOLVE_NO_XDEV logic hopefully becomes more clear:
> now we immediately fail when we cross mountpoints.
> 
> I think this patchset should get to -fixes and stable trees.
> 
> I split everything to very small commits to make
> everything as bisectable as possible.

Thanks! But as said ealier in the thread folding the first three
preparatory patches is fine.

> 
> Minimal testing was performed. I tested that my original
> reproducer doesn't reproduce anymore. And I did boot-test
> with localmodconfig in qemu
> 
> I'm not very attached to this patchset. I. e. I will not be offended
> if someone else will submit different fix for this bug.
> 
> Askar Safin (4):
>   vfs: fs/namei.c: move cross-device check to traverse_mounts
>   vfs: fs/namei.c: remove LOOKUP_NO_XDEV check from handle_mounts
>   vfs: fs/namei.c: move cross-device check to __traverse_mounts
>   vfs: fs/namei.c: if RESOLVE_NO_XDEV passed to openat2, don't *trigger*
>     automounts
> 
>  fs/namei.c | 29 +++++++++++++++++++++++------
>  1 file changed, 23 insertions(+), 6 deletions(-)
> 
> -- 
> 2.47.2
> 

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH 0/4] vfs: if RESOLVE_NO_XDEV passed to openat2, don't *trigger* automounts
  2025-08-19  8:24 ` Christian Brauner
@ 2025-08-20 18:04   ` Askar Safin
  0 siblings, 0 replies; 17+ messages in thread
From: Askar Safin @ 2025-08-20 18:04 UTC (permalink / raw)
  To: Christian Brauner
  Cc: Alexander Viro, Jan Kara, cyphar, Ian Kent, linux-fsdevel,
	David Howells, autofs mailing list, patches

 ---- On Tue, 19 Aug 2025 12:24:22 +0400  Christian Brauner <brauner@kernel.org> wrote --- 
 > Thanks, this looks all sane. Once you've addressed all comments I'll get
 > this into -next.

Thank you! I will write next version.

Please, also look at this Lichen Liu's patch:
https://lore.kernel.org/linux-fsdevel/20250815121459.3391223-1-lichliu@redhat.com/
I want this patch to succeed.

--
Askar Safin
https://types.pl/@safinaskar


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH 0/4] vfs: if RESOLVE_NO_XDEV passed to openat2, don't *trigger* automounts
  2025-08-19  8:21   ` Christian Brauner
@ 2025-08-25 12:46     ` Askar Safin
  2025-08-25 13:14       ` Christian Brauner
  0 siblings, 1 reply; 17+ messages in thread
From: Askar Safin @ 2025-08-25 12:46 UTC (permalink / raw)
  To: Christian Brauner
  Cc: Aleksa Sarai, Alexander Viro, Jan Kara, Ian Kent, linux-fsdevel,
	David Howells, autofs mailing list, patches


 ---- On Tue, 19 Aug 2025 12:21:33 +0400  Christian Brauner <brauner@kernel.org> wrote --- 
 > On Mon, Aug 18, 2025 at 03:31:27PM +1000, Aleksa Sarai wrote:
 > > I would merge the first three patches -- adding and removing code like
 > Agreed.

May I still not merge these patches?

All they may (hypothetically) fail on their own.

If they do, then it will be valuable to know from bisection which of them failed.

Let's discuss them one-by-one.

The first patch moves checks from handle_mounts to traverse_mounts.
But handle_mounts is not the only caller of traverse_mounts.
traverse_mounts is also called by follow_down.
I. e. theoretically follow_down-related code paths can lead to problems.
I just checked all them, none of them set LOOKUP_NO_XDEV.
So, they should not lead to problems. But in kernel we, of course, never
can be sure. They should not lead to problems, but still can.

The second patch removes LOOKUP_NO_XDEV check.
This is okay, because if "jumped" is set and "LOOKUP_NO_XDEV" is set, then
this means that we already set error, and thus ND_JUMPED should
not be read, because it is not read in error path. But this is not obvious, and
so Al asked me add comment (
https://lore.kernel.org/linux-fsdevel/20250817180057.GA222315@ZenIV/
), and, of course, I will add it in the second version in any case.
So, ND_JUMPED should not be checked in error path, and thus this should
not lead to problems. But still can.

The third patch makes traverse_mounts fail
immidiately after first mount-crossing
(if LOOKUP_NO_XDEV is set). As opposed to very end.
This should not lead to problems. But can.

So, again, any of these 3 patches can (hypothetically)
lead to its own problems.

So, for bisection reasons I want to keep them separate.

So, may I keep them separate?

(And I agree with all other complains in this thread, and will fix them in second version.)

--
Askar Safin
https://types.pl/@safinaskar


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH 0/4] vfs: if RESOLVE_NO_XDEV passed to openat2, don't *trigger* automounts
  2025-08-25 12:46     ` Askar Safin
@ 2025-08-25 13:14       ` Christian Brauner
  0 siblings, 0 replies; 17+ messages in thread
From: Christian Brauner @ 2025-08-25 13:14 UTC (permalink / raw)
  To: Askar Safin
  Cc: Aleksa Sarai, Alexander Viro, Jan Kara, Ian Kent, linux-fsdevel,
	David Howells, autofs mailing list, patches

On Mon, Aug 25, 2025 at 04:46:34PM +0400, Askar Safin wrote:
> 
>  ---- On Tue, 19 Aug 2025 12:21:33 +0400  Christian Brauner <brauner@kernel.org> wrote --- 
>  > On Mon, Aug 18, 2025 at 03:31:27PM +1000, Aleksa Sarai wrote:
>  > > I would merge the first three patches -- adding and removing code like
>  > Agreed.
> 
> May I still not merge these patches?
> 
> All they may (hypothetically) fail on their own.
> 
> If they do, then it will be valuable to know from bisection which of them failed.
> 
> Let's discuss them one-by-one.
> 
> The first patch moves checks from handle_mounts to traverse_mounts.
> But handle_mounts is not the only caller of traverse_mounts.
> traverse_mounts is also called by follow_down.
> I. e. theoretically follow_down-related code paths can lead to problems.
> I just checked all them, none of them set LOOKUP_NO_XDEV.
> So, they should not lead to problems. But in kernel we, of course, never
> can be sure. They should not lead to problems, but still can.
> 
> The second patch removes LOOKUP_NO_XDEV check.
> This is okay, because if "jumped" is set and "LOOKUP_NO_XDEV" is set, then
> this means that we already set error, and thus ND_JUMPED should
> not be read, because it is not read in error path. But this is not obvious, and
> so Al asked me add comment (
> https://lore.kernel.org/linux-fsdevel/20250817180057.GA222315@ZenIV/
> ), and, of course, I will add it in the second version in any case.
> So, ND_JUMPED should not be checked in error path, and thus this should
> not lead to problems. But still can.
> 
> The third patch makes traverse_mounts fail
> immidiately after first mount-crossing
> (if LOOKUP_NO_XDEV is set). As opposed to very end.
> This should not lead to problems. But can.
> 
> So, again, any of these 3 patches can (hypothetically)
> lead to its own problems.

You can send them separately if you like but I'll still reserve the
right to squash them when applying. I don't see the value in these
minimal changes yet and the regression potential is completely
theoretical so far.

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH 4/4] vfs: fs/namei.c: if RESOLVE_NO_XDEV passed to openat2, don't *trigger* automounts
  2025-08-18  7:15     ` Aleksa Sarai
@ 2025-08-25 17:48       ` Askar Safin
  0 siblings, 0 replies; 17+ messages in thread
From: Askar Safin @ 2025-08-25 17:48 UTC (permalink / raw)
  To: Aleksa Sarai
  Cc: Alexander Viro, Christian Brauner, Jan Kara, Ian Kent,
	linux-fsdevel, David Howells, autofs mailing list, patches

 ---- On Mon, 18 Aug 2025 11:15:16 +0400  Aleksa Sarai <cyphar@cyphar.com> wrote --- 
 > but we should have O_PATH|O_DIRECTORY produce
 > identical behaviour to O_PATH in this case IMHO.

I agree.

Original intention of autofs was so: stat should not trigger automounts
in final component, and everything else - should trigger (by default).
See
https://elixir.bootlin.com/linux/v6.17-rc2/source/Documentation/filesystems/autofs.rst#L93
.

So, yes, theoretically both O_PATH and O_PATH | O_DIRECTORY
should follow automounts (and nearly all other syscalls should, too).

--
Askar Safin
https://types.pl/@safinaskar


^ permalink raw reply	[flat|nested] 17+ messages in thread

end of thread, other threads:[~2025-08-25 17:48 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-08-17 17:15 [PATCH 0/4] vfs: if RESOLVE_NO_XDEV passed to openat2, don't *trigger* automounts Askar Safin
2025-08-17 17:15 ` [PATCH 1/4] vfs: fs/namei.c: move cross-device check to traverse_mounts Askar Safin
2025-08-17 17:15 ` [PATCH 2/4] vfs: fs/namei.c: remove LOOKUP_NO_XDEV check from handle_mounts Askar Safin
2025-08-17 18:00   ` Al Viro
2025-08-17 17:15 ` [PATCH 3/4] vfs: fs/namei.c: move cross-device check to __traverse_mounts Askar Safin
2025-08-17 17:15 ` [PATCH 4/4] vfs: fs/namei.c: if RESOLVE_NO_XDEV passed to openat2, don't *trigger* automounts Askar Safin
2025-08-17 17:53   ` Al Viro
2025-08-17 17:54     ` Al Viro
2025-08-18  5:17   ` Aleksa Sarai
2025-08-18  7:15     ` Aleksa Sarai
2025-08-25 17:48       ` Askar Safin
2025-08-18  5:31 ` [PATCH 0/4] vfs: " Aleksa Sarai
2025-08-19  8:21   ` Christian Brauner
2025-08-25 12:46     ` Askar Safin
2025-08-25 13:14       ` Christian Brauner
2025-08-19  8:24 ` Christian Brauner
2025-08-20 18:04   ` Askar Safin

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).