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