The branch, master has been updated
       via  6c3ee9747a4 vfs:streams_xattr: Allow VFS_OPEN_HOW_RESOLVE_NO_XDEV
       via  15836962ecc vfs:fruit: Allow RESOLVE_NO_XDEV flag
       via  18b283f83e7 vfs:streams_depot: Allow VFS_OPEN_HOW_RESOLVE_NO_XDEV 
flag
       via  249e335d694 vfs:shadow_copy2: Allow RESOLVE_NO_XDEV flag
       via  e67b08191cd vfs:glusterfs: Allow VFS_OPEN_HOW_RESOLVE_NO_XDEV
       via  93111820133 vfs:ceph_new: Allow VFS_OPEN_HOW_RESOLVE_NO_XDEV flag
       via  458fd85d5aa vfs:ceph: Allow VFS_OPEN_HOW_RESOLVE_NO_XDEV flag
       via  71baa41073a vfs:aio_pthread: Handle VFS_OPEN_HOW_RESOLVE_NO_XDEV 
flag
       via  82cb952f452 smbd: Fix crossing direct automounter mount points
       via  39d51636d81 smbd: Refactor reopen_from_fsp(), factor out pathref 
based
       via  4fce96afa63 smbd: Refactor reopen_from_fsp(), factor out 
automounter mountpoint check
       via  dc0a6a3a69b smbd: Refactor reopen_from_fsp(), factor out name based 
reopen
       via  cb826fc4fd9 vfs: Pass the RESOLVE_NO_XDEV from upper layers to 
openat2() syscall
       via  17f1c5d8cb1 selftest/Samba3: nt4_dc* use 
vfs_default:VFS_OPEN_HOW_RESOLVE_NO_XDEV=no
       via  862d16cee8c vfs: Use RESOLVE_NO_XDEV by default on all shares
       via  ac2698131fb vfs: Bump VFS interface version after adding 
VFS_OPEN_HOW_RESOLVE_NO_XDEV
       via  aac78b21423 vfs: Add VFS_OPEN_HOW_RESOLVE_NO_XDEV flag
      from  ef3f44a1de1 ci: Don't run on private rackspace runner

https://git.samba.org/?p=samba.git;a=shortlog;h=master


- Log -----------------------------------------------------------------
commit 6c3ee9747a4ed0cba9c5046721c29372734cd3f5
Author: Samuel Cabrero <[email protected]>
Date:   Thu Oct 9 13:05:16 2025 +0200

    vfs:streams_xattr: Allow VFS_OPEN_HOW_RESOLVE_NO_XDEV
    
    The open function returns a fake fd. Extended attributes will be stored by
    vfs_xattr_tdb or vfs_default.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=15805
    
    Signed-off-by: Samuel Cabrero <[email protected]>
    Reviewed-by: Ralph Boehme <[email protected]>
    
    Autobuild-User(master): Samuel Cabrero <[email protected]>
    Autobuild-Date(master): Tue Nov 18 09:08:38 UTC 2025 on atb-devel-224

commit 15836962eccb4f91706cc1d4b56329bb936cc1d1
Author: Samuel Cabrero <[email protected]>
Date:   Thu Oct 9 12:59:59 2025 +0200

    vfs:fruit: Allow RESOLVE_NO_XDEV flag
    
    For stream opens, it returns a fake fd. The streams will be stored by
    vfs_streams_depot or vfs_streams_xattr.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=15805
    
    Signed-off-by: Samuel Cabrero <[email protected]>
    Reviewed-by: Ralph Boehme <[email protected]>

commit 18b283f83e7bb2501e1b2c75489852512a1bd4fd
Author: Samuel Cabrero <[email protected]>
Date:   Thu Oct 9 12:52:11 2025 +0200

    vfs:streams_depot: Allow VFS_OPEN_HOW_RESOLVE_NO_XDEV flag
    
    The flag is passed down the modules stack.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=15805
    
    Signed-off-by: Samuel Cabrero <[email protected]>
    Reviewed-by: Ralph Boehme <[email protected]>

commit 249e335d694350eea14d61889672effd43327427
Author: Samuel Cabrero <[email protected]>
Date:   Fri May 2 13:21:52 2025 +0200

    vfs:shadow_copy2: Allow RESOLVE_NO_XDEV flag
    
    This module updates the path and calls the next VFS module.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=15805
    
    Signed-off-by: Samuel Cabrero <[email protected]>
    Reviewed-by: Ralph Boehme <[email protected]>

commit e67b08191cd7f8ff10ba27826642da49f69332a0
Author: Samuel Cabrero <[email protected]>
Date:   Thu Oct 9 12:30:17 2025 +0200

    vfs:glusterfs: Allow VFS_OPEN_HOW_RESOLVE_NO_XDEV
    
    Don't return ENOSYS if the flag is set. It will be ignored as does not make
    sense in this module.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=15805
    
    Signed-off-by: Samuel Cabrero <[email protected]>
    Reviewed-by: Ralph Boehme <[email protected]>

commit 93111820133692b425c2a883f05a06b70c02a3f3
Author: Samuel Cabrero <[email protected]>
Date:   Tue Sep 30 10:32:36 2025 +0200

    vfs:ceph_new: Allow VFS_OPEN_HOW_RESOLVE_NO_XDEV flag
    
    Don't return ENOSYS if the flag is set. It will be ignored,
    does not make sense in a ceph filesystem.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=15805
    
    Signed-off-by: Samuel Cabrero <[email protected]>
    Reviewed-by: Ralph Boehme <[email protected]>

commit 458fd85d5aa2b3c41a0656b47d8c770c7f6c9957
Author: Samuel Cabrero <[email protected]>
Date:   Fri May 2 12:11:01 2025 +0200

    vfs:ceph: Allow VFS_OPEN_HOW_RESOLVE_NO_XDEV flag
    
    Don't return ENOSYS if the flag is set. It will be ignored,
    does not make sense in a ceph virtual filesystem.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=15805
    
    Signed-off-by: Samuel Cabrero <[email protected]>
    Reviewed-by: Ralph Boehme <[email protected]>

commit 71baa41073a1e2cf6fb88d7a20f8758843c7485b
Author: Samuel Cabrero <[email protected]>
Date:   Fri May 2 11:57:30 2025 +0200

    vfs:aio_pthread: Handle VFS_OPEN_HOW_RESOLVE_NO_XDEV flag
    
    This module uses openat() instead of openat2() so the flag won't be used and
    automounts might not be triggered.
    
    Disable flag usage for subsequent opens and return an error to callers to 
warn
    the user and retry without the flag.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=15805
    
    Signed-off-by: Samuel Cabrero <[email protected]>
    Reviewed-by: Ralph Boehme <[email protected]>

commit 82cb952f45215b053ba7e80bed008890968a1c76
Author: Samuel Cabrero <[email protected]>
Date:   Wed Oct 8 17:09:22 2025 +0200

    smbd: Fix crossing direct automounter mount points
    
    The workaround implemented in commit 
ac7a16f9cc4bd97ef546d1b7b02605991000d0f9
    to trigger automounts does not work for direct automounts (either with
    systemd-automount or autofs daemon).
    
    In direct automounts the mount point is a real directory instead of a 
"ghost"
    directory so when turning the O_PATH handle into a real one through
    /proc/self/fd/<fdnum> openat() does not return ENOENT, it returs a fd 
referring
    to the mount point without triggering the mount.
    
    To trigger the mount first we have to know when we are crossing mount points
    by using the RESOLVE_NO_XDEV flag in open_how.resolve, then we can check 
with
    fstatfs() the .f_type and fallback to a path-based open for automounts or
    retry without RESOLVE_NO_XDEV otherwise.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=15805
    
    Signed-off-by: Samuel Cabrero <[email protected]>
    Reviewed-by: Ralph Boehme <[email protected]>

commit 39d51636d81f707899b0bc1c76d1ad7ae4a9c9fe
Author: Samuel Cabrero <[email protected]>
Date:   Wed Oct 8 14:17:27 2025 +0200

    smbd: Refactor reopen_from_fsp(), factor out pathref based
    
    Best viewed ignoring white space changes
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=15805
    
    Signed-off-by: Samuel Cabrero <[email protected]>
    Reviewed-by: Ralph Boehme <[email protected]>

commit 4fce96afa638eba8f301db8997ad034e83d94a8b
Author: Samuel Cabrero <[email protected]>
Date:   Wed Oct 8 13:53:14 2025 +0200

    smbd: Refactor reopen_from_fsp(), factor out automounter mountpoint check
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=15805
    
    Signed-off-by: Samuel Cabrero <[email protected]>
    Reviewed-by: Ralph Boehme <[email protected]>

commit dc0a6a3a69b1ac09e4b8981b1bde851e3d55d5ed
Author: Samuel Cabrero <[email protected]>
Date:   Wed Oct 8 13:18:44 2025 +0200

    smbd: Refactor reopen_from_fsp(), factor out name based reopen
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=15805
    
    Signed-off-by: Samuel Cabrero <[email protected]>
    Reviewed-by: Ralph Boehme <[email protected]>

commit cb826fc4fd9265683db93c9b7cfbf97edfb322a7
Author: Samuel Cabrero <[email protected]>
Date:   Fri Feb 14 17:14:59 2025 +0100

    vfs: Pass the RESOLVE_NO_XDEV from upper layers to openat2() syscall
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=15805
    
    Signed-off-by: Samuel Cabrero <[email protected]>
    Reviewed-by: Ralph Boehme <[email protected]>

commit 17f1c5d8cb16fce9f96ce9556b70b0082bbdbd4e
Author: Samuel Cabrero <[email protected]>
Date:   Wed Oct 8 10:54:55 2025 +0200

    selftest/Samba3: nt4_dc* use vfs_default:VFS_OPEN_HOW_RESOLVE_NO_XDEV=no
    
    From 076c22fbd7ecbf22dbfeb1711609f07fd42f88b0, we should always test the
    code path without openat2 being available, even if the kernel supports it.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=15805
    
    Signed-off-by: Samuel Cabrero <[email protected]>
    Reviewed-by: Ralph Boehme <[email protected]>

commit 862d16cee8c7fd6804bfd6a6e948fe78c5b1b837
Author: Samuel Cabrero <[email protected]>
Date:   Fri Feb 14 17:13:39 2025 +0100

    vfs: Use RESOLVE_NO_XDEV by default on all shares
    
    Enable the flag by default on all shares, it will be automatically
    disabled if the system does not support openat2().
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=15805
    
    Signed-off-by: Samuel Cabrero <[email protected]>
    Reviewed-by: Ralph Boehme <[email protected]>

commit ac2698131fbfeb41cc9a57905574210f09faeba1
Author: Samuel Cabrero <[email protected]>
Date:   Wed Oct 8 10:39:25 2025 +0200

    vfs: Bump VFS interface version after adding VFS_OPEN_HOW_RESOLVE_NO_XDEV
    
    If a module was compiled with an older version it won't handle the new flag.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=15805
    
    Signed-off-by: Samuel Cabrero <[email protected]>
    Reviewed-by: Ralph Boehme <[email protected]>

commit aac78b2142392a212e5b047225d50612da82a953
Author: Samuel Cabrero <[email protected]>
Date:   Fri Feb 14 17:07:14 2025 +0100

    vfs: Add VFS_OPEN_HOW_RESOLVE_NO_XDEV flag
    
    It disallows traversal of mount points during path resolution, including 
bind
    mounts.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=15805
    
    Signed-off-by: Samuel Cabrero <[email protected]>
    Reviewed-by: Ralph Boehme <[email protected]>

-----------------------------------------------------------------------

Summary of changes:
 script/autobuild.py                 |   2 +-
 selftest/target/Samba3.pm           |   1 +
 source3/include/vfs.h               |   4 +-
 source3/modules/vfs_aio_pthread.c   |  14 ++-
 source3/modules/vfs_ceph.c          |   4 +-
 source3/modules/vfs_ceph_new.c      |   4 +-
 source3/modules/vfs_default.c       |  30 ++++-
 source3/modules/vfs_fruit.c         |   4 +-
 source3/modules/vfs_glusterfs.c     |   4 +-
 source3/modules/vfs_shadow_copy2.c  |   4 +-
 source3/modules/vfs_streams_depot.c |   4 +-
 source3/modules/vfs_streams_xattr.c |   4 +-
 source3/smbd/open.c                 | 241 ++++++++++++++++++++++++++----------
 13 files changed, 243 insertions(+), 77 deletions(-)


Changeset truncated at 500 lines:

diff --git a/script/autobuild.py b/script/autobuild.py
index feaafebe9e2..08abd398810 100755
--- a/script/autobuild.py
+++ b/script/autobuild.py
@@ -333,7 +333,7 @@ tasks = {
     "samba-no-opath-build": {
         "git-clone-required": True,
         "sequence": [
-            ("configure", "ADDITIONAL_CFLAGS='-DDISABLE_OPATH=1 
-DDISABLE_VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS=1 -DDISABLE_PROC_FDS=1' 
./configure.developer --without-ad-dc " + samba_configure_params),
+            ("configure", "ADDITIONAL_CFLAGS='-DDISABLE_OPATH=1 
-DDISABLE_VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS=1 
-DDISABLE_VFS_OPEN_HOW_RESOLVE_NO_XDEV=1 -DDISABLE_PROC_FDS=1' 
./configure.developer --without-ad-dc " + samba_configure_params),
             ("make", "make -j"),
             ("check-clean-tree", CLEAN_SOURCE_TREE_CMD),
             ("chmod-R-a-w", "chmod -R a-w ."),
diff --git a/selftest/target/Samba3.pm b/selftest/target/Samba3.pm
index 5595902473b..ee1d8802223 100755
--- a/selftest/target/Samba3.pm
+++ b/selftest/target/Samba3.pm
@@ -304,6 +304,7 @@ sub setup_nt4_dc
        server schannel require seal:torturetest\$ = no
 
        vfs_default:VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS = no
+       vfs_default:VFS_OPEN_HOW_RESOLVE_NO_XDEV = no
 
        fss: sequence timeout = 1
        check parent directory delete on close = yes
diff --git a/source3/include/vfs.h b/source3/include/vfs.h
index e99d84e36f8..3922b638323 100644
--- a/source3/include/vfs.h
+++ b/source3/include/vfs.h
@@ -396,9 +396,10 @@
  * Version 52 - Add rename_stream
  * Version 52 - Remove connectpath
  * Version 52 - Remove audit_file
+ * Version 52 - Add VFS_OPEN_HOW_RESOLVE_NO_XDEV for SMB_VFS_OPENAT()
  */
 
-#define SMB_VFS_INTERFACE_VERSION 51
+#define SMB_VFS_INTERFACE_VERSION 52
 
 /*
     All intercepted VFS operations must be declared as static functions inside 
module source
@@ -933,6 +934,7 @@ struct vfs_aio_state {
 
 #define VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS 1
 #define VFS_OPEN_HOW_WITH_BACKUP_INTENT 2
+#define VFS_OPEN_HOW_RESOLVE_NO_XDEV 4
 
 struct vfs_open_how {
        int flags;
diff --git a/source3/modules/vfs_aio_pthread.c 
b/source3/modules/vfs_aio_pthread.c
index bd0c94b8cce..afbaaedf7b5 100644
--- a/source3/modules/vfs_aio_pthread.c
+++ b/source3/modules/vfs_aio_pthread.c
@@ -457,7 +457,9 @@ static int aio_pthread_openat_fn(vfs_handle_struct *handle,
        bool aio_allow_open = lp_parm_bool(
                SNUM(handle->conn), "aio_pthread", "aio open", false);
 
-       if ((how->resolve & ~VFS_OPEN_HOW_WITH_BACKUP_INTENT) != 0) {
+       if ((how->resolve & ~(VFS_OPEN_HOW_WITH_BACKUP_INTENT |
+                             VFS_OPEN_HOW_RESOLVE_NO_XDEV)) != 0)
+       {
                errno = ENOSYS;
                return -1;
        }
@@ -498,6 +500,16 @@ static int aio_pthread_openat_fn(vfs_handle_struct *handle,
                aio_allow_open = false;
        }
 
+       if (how->resolve & VFS_OPEN_HOW_RESOLVE_NO_XDEV) {
+               /*
+                * RESOLVE_NO_XDEV needs openat2(). Disallow further usage of
+                * this flag and return ENOSYS to force a retry.
+                */
+               fsp->conn->open_how_resolve &= ~VFS_OPEN_HOW_RESOLVE_NO_XDEV;
+               errno = ENOSYS;
+               return -1;
+       }
+
        if (!aio_allow_open) {
                /* aio opens turned off. */
                return SMB_VFS_NEXT_OPENAT(handle,
diff --git a/source3/modules/vfs_ceph.c b/source3/modules/vfs_ceph.c
index dc10a516ff5..04d7433c1e0 100644
--- a/source3/modules/vfs_ceph.c
+++ b/source3/modules/vfs_ceph.c
@@ -472,7 +472,9 @@ static int cephwrap_openat(struct vfs_handle_struct *handle,
        int result = -ENOENT;
        int dirfd = -1;
 
-       if ((how->resolve & ~VFS_OPEN_HOW_WITH_BACKUP_INTENT) != 0) {
+       if ((how->resolve & ~(VFS_OPEN_HOW_WITH_BACKUP_INTENT |
+                             VFS_OPEN_HOW_RESOLVE_NO_XDEV)) != 0)
+       {
                errno = ENOSYS;
                return -1;
        }
diff --git a/source3/modules/vfs_ceph_new.c b/source3/modules/vfs_ceph_new.c
index 5dfdea583e9..2da722fcc80 100644
--- a/source3/modules/vfs_ceph_new.c
+++ b/source3/modules/vfs_ceph_new.c
@@ -2335,7 +2335,9 @@ static int vfs_ceph_openat(struct vfs_handle_struct 
*handle,
        int result = -ENOENT;
 
        START_PROFILE_X(SNUM(handle->conn), syscall_openat);
-       if ((how->resolve & ~VFS_OPEN_HOW_WITH_BACKUP_INTENT) != 0) {
+       if ((how->resolve & ~(VFS_OPEN_HOW_WITH_BACKUP_INTENT |
+                             VFS_OPEN_HOW_RESOLVE_NO_XDEV)) != 0)
+       {
                result = -ENOSYS;
                goto err_out;
        }
diff --git a/source3/modules/vfs_default.c b/source3/modules/vfs_default.c
index 34b00f5b547..266fa87b3ed 100644
--- a/source3/modules/vfs_default.c
+++ b/source3/modules/vfs_default.c
@@ -76,6 +76,17 @@ static int vfswrap_connect(vfs_handle_struct *handle, const 
char *service, const
 #ifdef DISABLE_VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS
        handle->conn->open_how_resolve &= ~VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS;
 #endif
+       bval = lp_parm_bool(SNUM(handle->conn),
+                           "vfs_default",
+                           "VFS_OPEN_HOW_RESOLVE_NO_XDEV",
+                           true);
+       if (bval) {
+               handle->conn->open_how_resolve |=
+                       VFS_OPEN_HOW_RESOLVE_NO_XDEV;
+       }
+#ifdef DISABLE_VFS_OPEN_HOW_RESOLVE_NO_XDEV
+       handle->conn->open_how_resolve &= ~VFS_OPEN_HOW_RESOLVE_NO_XDEV;
+#endif
 
        return 0;    /* Return >= 0 for success */
 }
@@ -617,7 +628,9 @@ static int vfswrap_openat(vfs_handle_struct *handle,
        SMB_ASSERT((dirfd != -1) || (smb_fname->base_name[0] == '/'));
 
        if (how->resolve & ~(VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS |
-                            VFS_OPEN_HOW_WITH_BACKUP_INTENT)) {
+                            VFS_OPEN_HOW_WITH_BACKUP_INTENT |
+                            VFS_OPEN_HOW_RESOLVE_NO_XDEV))
+       {
                errno = ENOSYS;
                result = -1;
                goto out;
@@ -650,12 +663,20 @@ static int vfswrap_openat(vfs_handle_struct *handle,
        }
 #endif
 
-       if (how->resolve & VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS) {
+       if (how->resolve & VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS ||
+           how->resolve & VFS_OPEN_HOW_RESOLVE_NO_XDEV)
+       {
                struct open_how linux_how = {
                        .flags = flags,
                        .mode = mode,
-                       .resolve = RESOLVE_NO_SYMLINKS,
+                       .resolve = 0,
                };
+               if (how->resolve & VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS) {
+                       linux_how.resolve |= RESOLVE_NO_SYMLINKS;
+               }
+               if (how->resolve & VFS_OPEN_HOW_RESOLVE_NO_XDEV) {
+                       linux_how.resolve |= RESOLVE_NO_XDEV;
+               }
 
                result = openat2(dirfd,
                                 smb_fname->base_name,
@@ -668,10 +689,13 @@ static int vfswrap_openat(vfs_handle_struct *handle,
                                 * openat2(), so indicate to
                                 * the callers that
                                 * VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS
+                                * or VFS_OPEN_HOW_RESOLVE_NO_XDEV
                                 * would just be a waste of time.
                                 */
                                fsp->conn->open_how_resolve &=
                                        ~VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS;
+                               fsp->conn->open_how_resolve &=
+                                       ~VFS_OPEN_HOW_RESOLVE_NO_XDEV;
                        }
                        goto out;
                }
diff --git a/source3/modules/vfs_fruit.c b/source3/modules/vfs_fruit.c
index 9a634bab758..933e00418a9 100644
--- a/source3/modules/vfs_fruit.c
+++ b/source3/modules/vfs_fruit.c
@@ -1763,7 +1763,9 @@ static int fruit_openat(vfs_handle_struct *handle,
                return fd;
        }
 
-       if ((how->resolve & ~VFS_OPEN_HOW_WITH_BACKUP_INTENT) != 0) {
+       if ((how->resolve & ~(VFS_OPEN_HOW_WITH_BACKUP_INTENT |
+                             VFS_OPEN_HOW_RESOLVE_NO_XDEV)) != 0)
+       {
                errno = ENOSYS;
                return -1;
        }
diff --git a/source3/modules/vfs_glusterfs.c b/source3/modules/vfs_glusterfs.c
index 6fe12985d9c..9293f7ee996 100644
--- a/source3/modules/vfs_glusterfs.c
+++ b/source3/modules/vfs_glusterfs.c
@@ -731,7 +731,9 @@ static int vfs_gluster_openat(struct vfs_handle_struct 
*handle,
 
        START_PROFILE(syscall_openat);
 
-       if ((how->resolve & ~VFS_OPEN_HOW_WITH_BACKUP_INTENT) != 0) {
+       if ((how->resolve & ~(VFS_OPEN_HOW_WITH_BACKUP_INTENT |
+                             VFS_OPEN_HOW_RESOLVE_NO_XDEV)) != 0)
+       {
                END_PROFILE(syscall_openat);
                errno = ENOSYS;
                return -1;
diff --git a/source3/modules/vfs_shadow_copy2.c 
b/source3/modules/vfs_shadow_copy2.c
index 17e2b84d7bd..8e9b6701cb1 100644
--- a/source3/modules/vfs_shadow_copy2.c
+++ b/source3/modules/vfs_shadow_copy2.c
@@ -1558,7 +1558,9 @@ static int shadow_copy2_openat(vfs_handle_struct *handle,
        int ret;
        bool ok;
 
-       if ((how.resolve & ~VFS_OPEN_HOW_WITH_BACKUP_INTENT) != 0) {
+       if ((how.resolve & ~(VFS_OPEN_HOW_WITH_BACKUP_INTENT |
+                            VFS_OPEN_HOW_RESOLVE_NO_XDEV)) != 0)
+       {
                errno = ENOSYS;
                return -1;
        }
diff --git a/source3/modules/vfs_streams_depot.c 
b/source3/modules/vfs_streams_depot.c
index 279f1289d4a..4d16079ea89 100644
--- a/source3/modules/vfs_streams_depot.c
+++ b/source3/modules/vfs_streams_depot.c
@@ -729,7 +729,9 @@ static int streams_depot_openat(struct vfs_handle_struct 
*handle,
                        handle, dirfsp, smb_fname, fsp, how);
        }
 
-       if ((how->resolve & ~VFS_OPEN_HOW_WITH_BACKUP_INTENT) != 0) {
+       if ((how->resolve & ~(VFS_OPEN_HOW_WITH_BACKUP_INTENT |
+                             VFS_OPEN_HOW_RESOLVE_NO_XDEV)) != 0)
+       {
                errno = ENOSYS;
                return -1;
        }
diff --git a/source3/modules/vfs_streams_xattr.c 
b/source3/modules/vfs_streams_xattr.c
index f892bc45c66..5d267a1c1fb 100644
--- a/source3/modules/vfs_streams_xattr.c
+++ b/source3/modules/vfs_streams_xattr.c
@@ -901,7 +901,9 @@ static int streams_xattr_openat(struct vfs_handle_struct 
*handle,
                                           how);
        }
 
-       if ((how->resolve & ~VFS_OPEN_HOW_WITH_BACKUP_INTENT) != 0) {
+       if ((how->resolve & ~(VFS_OPEN_HOW_WITH_BACKUP_INTENT |
+                             VFS_OPEN_HOW_RESOLVE_NO_XDEV)) != 0)
+       {
                errno = ENOSYS;
                return -1;
        }
diff --git a/source3/smbd/open.c b/source3/smbd/open.c
index 5294d0c9c9d..02f3c53598f 100644
--- a/source3/smbd/open.c
+++ b/source3/smbd/open.c
@@ -845,91 +845,204 @@ static NTSTATUS fd_open_atomic(struct files_struct 
*dirfsp,
        return status;
 }
 
-NTSTATUS reopen_from_fsp(struct files_struct *dirfsp,
-                        struct smb_filename *smb_fname,
-                        struct files_struct *fsp,
-                        const struct vfs_open_how *how,
-                        bool *p_file_created)
+/*
+ * Close the existing pathref fd and set the fsp flag
+ * is_pathref to false so we get a "normal" fd this time.
+ */
+static NTSTATUS reopen_from_fsp_namebased(struct files_struct *dirfsp,
+                                         struct smb_filename *smb_fname,
+                                         struct files_struct *fsp,
+                                         const struct vfs_open_how *how,
+                                         bool *p_file_created)
 {
        NTSTATUS status;
-       int old_fd;
-
-       if (fsp->fsp_flags.have_proc_fds &&
-           ((old_fd = fsp_get_pathref_fd(fsp)) != -1)) {
 
-               struct sys_proc_fd_path_buf buf;
-               struct smb_filename proc_fname = {
-                       .base_name = sys_proc_fd_path(old_fd, &buf),
-               };
-               mode_t mode = fsp->fsp_name->st.st_ex_mode;
-               int new_fd;
+       status = fd_close(fsp);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
 
-               if (S_ISLNK(mode)) {
-                       return NT_STATUS_STOPPED_ON_SYMLINK;
-               }
-               if (!(S_ISREG(mode) || S_ISDIR(mode))) {
-                       return NT_STATUS_IO_REPARSE_TAG_NOT_HANDLED;
-               }
+       fsp->fsp_flags.is_pathref = false;
 
-               fsp->fsp_flags.is_pathref = false;
+       status = fd_open_atomic(dirfsp,
+                               smb_fname,
+                               fsp,
+                               how,
+                               p_file_created);
+       return status;
+}
 
-               new_fd = SMB_VFS_OPENAT(fsp->conn,
-                                       fsp->conn->cwd_fsp,
-                                       &proc_fname,
-                                       fsp,
-                                       how);
-               if (new_fd == -1) {
+static bool fsp_is_automount_mountpoint(struct files_struct *fsp, int old_fd)
+{
 #if defined(HAVE_FSTATFS) && defined(HAVE_LINUX_MAGIC_H)
-                       if (S_ISDIR(fsp->fsp_name->st.st_ex_mode) &&
-                           (errno == ENOENT)) {
-                               struct statfs sbuf = {};
-                               int ret = fstatfs(old_fd, &sbuf);
-                               if (ret == -1) {
-                                       DBG_ERR("fstatfs failed: %s\n",
-                                               strerror(errno));
-                               } else if (sbuf.f_type == AUTOFS_SUPER_MAGIC) {
-                                       /*
-                                        * When reopening an as-yet
-                                        * unmounted autofs mount
-                                        * point we get ENOENT. We
-                                        * have to retry pathbased.
-                                        */
-                                       goto namebased_open;
-                               }
-                               /* restore ENOENT if changed in the meantime */
-                               errno = ENOENT;
-                       }
+       struct statfs sbuf = {};
+       int ret;
+
+       if (!S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
+               return false;
+       }
+
+       ret = fstatfs(old_fd, &sbuf);
+       if (ret == -1) {
+               DBG_ERR("fstatfs failed: %s\n", strerror(errno));
+               return false;
+       }
+       if (sbuf.f_type == AUTOFS_SUPER_MAGIC) {
+               return true;
+       }
+       return false;
+#else
+       return false;
 #endif
-                       status = map_nt_error_from_unix(errno);
-                       fd_close(fsp);
-                       return status;
-               }
+}
 
-               status = fd_close(fsp);
-               if (!NT_STATUS_IS_OK(status)) {
-                       return status;
-               }
+static NTSTATUS reopen_from_fsp_pathref_based(
+       struct files_struct *dirfsp,
+       struct smb_filename *smb_fname,
+       struct files_struct *fsp,
+       const struct vfs_open_how *how,
+       bool *p_file_created)
+{
+       NTSTATUS status;
+       struct sys_proc_fd_path_buf buf;
+       int pathref_fd = fsp_get_pathref_fd(fsp);
+       struct smb_filename proc_fname = {
+               .base_name = sys_proc_fd_path(pathref_fd, &buf),
+       };
+       mode_t mode = fsp->fsp_name->st.st_ex_mode;
+       int new_fd;
+       struct vfs_open_how pathref_how = *how;
 
-               fsp_set_fd(fsp, new_fd);
-               return NT_STATUS_OK;
+       if (S_ISLNK(mode)) {
+               return NT_STATUS_STOPPED_ON_SYMLINK;
+       }
+       if (!(S_ISREG(mode) || S_ISDIR(mode))) {
+               return NT_STATUS_IO_REPARSE_TAG_NOT_HANDLED;
        }
 
+       fsp->fsp_flags.is_pathref = false;
+
 #if defined(HAVE_FSTATFS) && defined(HAVE_LINUX_MAGIC_H)
-namebased_open:
-#endif
        /*
-        * Close the existing pathref fd and set the fsp flag
-        * is_pathref to false so we get a "normal" fd this time.
+        * There is no point in setting RESOLVE_NO_XDEV if we can't
+        * check with fstatfs later in fsp_is_automount_mountpoint
         */
+       if (S_ISDIR(fsp->fsp_name->st.st_ex_mode) &&
+           fsp->conn->open_how_resolve & VFS_OPEN_HOW_RESOLVE_NO_XDEV) {
+               /*
+                * If the *at cwd_fsp is a pathref (opened with O_PATH)
+                * and old_fd refers to an automounter mount point not
+                * yet mounted, we will get a fd referring to the
+                * mount point without actually triggering the mount
+                * (man 2 openat). To detect this situation set the
+                * RESOLVE_NO_XDEV flag so openat2 will return an
+                * error when crossing mount points. Then check
+                * with fstatfs if it is an autofs mount point or not,
+                * falling back to name-based openat or retry without
+                * RESOLVE_NO_XDEV otherwise (could be a bind mount,
+                * other type of mount of an automounter mount point
+                * already mounted).
+                */
+               pathref_how.resolve |= VFS_OPEN_HOW_RESOLVE_NO_XDEV;
+       }
+#endif
+
+retry:
+       new_fd = SMB_VFS_OPENAT(fsp->conn,
+                               fsp->conn->cwd_fsp,
+                               &proc_fname,
+                               fsp,
+                               &pathref_how);
+       if (new_fd == -1) {
+               int saved_errno = errno;
+               if (saved_errno == ENOENT &&
+                   fsp_is_automount_mountpoint(fsp, pathref_fd))
+               {
+                       /*
+                        * This is a not yet triggered indirect automount
+                        * detected by openat(pathref_fd). Retry name-based.
+                        */
+                       return reopen_from_fsp_namebased(dirfsp,
+                                                        smb_fname,
+                                                        fsp,
+                                                        how,
+                                                        p_file_created);
+               } else if (saved_errno == EXDEV &&
+                   pathref_how.resolve & VFS_OPEN_HOW_RESOLVE_NO_XDEV &&
+                   fsp_is_automount_mountpoint(fsp, pathref_fd))
+               {
+                       /*
+                        * This is a not yet triggered direct or indirect
+                        * automount, detected by
+                        * openat2(pathref_fd, .., RESOLVE_NO_XDEV).
+                        * Retry name-based.
+                        */
+                       return reopen_from_fsp_namebased(dirfsp,
+                                                        smb_fname,
+                                                        fsp,
+                                                        how,
+                                                        p_file_created);
+               } else if (saved_errno == ENOSYS &&
+                   pathref_how.resolve & VFS_OPEN_HOW_RESOLVE_NO_XDEV)
+               {
+                       /*
+                        * The kernel doesn't support openat2() yet, or any
+                        * VFS module rejected the flag. Notify to the user
+                        * and retry without RESOLVE_NO_XDEV.
+                        */
+                       DBG_WARNING("Failed to open directory disallowing the "
+                                   "traversal of mount points during path "
+                                   "resolution. Retrying allowing traversal, "
+                                   "but automounts won't be triggered.\n");
+                       pathref_how.resolve &= ~VFS_OPEN_HOW_RESOLVE_NO_XDEV;
+                       goto retry;
+               } else if (saved_errno == EXDEV &&
+                   pathref_how.resolve & VFS_OPEN_HOW_RESOLVE_NO_XDEV)
+               {
+                       /*
+                        * Just crossing a mount. Retry allowing traversals.
+                        */
+                       pathref_how.resolve &= ~VFS_OPEN_HOW_RESOLVE_NO_XDEV;
+                       goto retry;
+               }
+
+               status = map_nt_error_from_unix(saved_errno);
+               fd_close(fsp);
+               return status;
+       }
+
        status = fd_close(fsp);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
 
-       fsp->fsp_flags.is_pathref = false;
+       fsp_set_fd(fsp, new_fd);
+       return NT_STATUS_OK;
+}


-- 
Samba Shared Repository

Reply via email to