From 32574e3621fdda3e83759479f3dcfdba6511c42b Mon Sep 17 00:00:00 2001 From: Andrew Walker Date: Thu, 2 Mar 2023 08:20:34 -0500 Subject: [PATCH] Add O_RESOLVE_NO_SYMLINKS This is required for Samba 4.17 and higher. Internally samba uses the openat2 flag RESOLVE_NO_SYMLINKS as an optimization to create a fast-path for opening files that helps mitigate some of Samba 4.13+ metadata performance regression due to symlink safety checks. This commit adds an open flag equivalent to MNT_NOSYMLFOLLOW mount flag. --- sys/kern/vfs_lookup.c | 8 ++++++++ sys/kern/vfs_vnops.c | 2 ++ sys/sys/fcntl.h | 1 + sys/sys/namei.h | 1 + 4 files changed, 12 insertions(+) diff --git a/sys/kern/vfs_lookup.c b/sys/kern/vfs_lookup.c index 3ded2180ac82b..be5f8d2774de3 100644 --- a/sys/kern/vfs_lookup.c +++ b/sys/kern/vfs_lookup.c @@ -74,6 +74,9 @@ __FBSDID("$FreeBSD$"); #define NAMEI_DIAGNOSTIC 1 #undef NAMEI_DIAGNOSTIC +FEATURE(rnosymlink, "supports RESOLVE_NO_SYMLINK"); +FEATURE(rbeneath, "supports RESOLVE_BENEATH"); + SDT_PROVIDER_DEFINE(vfs); SDT_PROBE_DEFINE4(vfs, namei, lookup, entry, "struct vnode *", "char *", "unsigned long", "bool"); @@ -1192,6 +1195,11 @@ lookup(struct nameidata *ndp) error = ENOENT; goto bad2; } + if (cnp->cn_flags & RNOSYMLINK) { + /* Linux openat2() behavior for RESOLVE_NO_SYMLINKS */ + error = ELOOP; + goto bad2; + } if (dp->v_mount->mnt_flag & MNT_NOSYMFOLLOW) { error = EACCES; goto bad2; diff --git a/sys/kern/vfs_vnops.c b/sys/kern/vfs_vnops.c index f4274ee38689e..fb1f9d31609fe 100644 --- a/sys/kern/vfs_vnops.c +++ b/sys/kern/vfs_vnops.c @@ -201,6 +201,8 @@ open2nameif(int fmode, u_int vn_open_flags) res = ISOPEN | LOCKLEAF; if ((fmode & O_RESOLVE_BENEATH) != 0) res |= RBENEATH; + if ((fmode & O_RESOLVE_NO_SYMLINKS) != 0) + res |= RNOSYMLINK; if ((fmode & O_EMPTY_PATH) != 0) res |= EMPTYPATH; if ((vn_open_flags & VN_OPEN_NOAUDIT) == 0) diff --git a/sys/sys/fcntl.h b/sys/sys/fcntl.h index 64aa6be3083fe..bb6551b47f49b 100644 --- a/sys/sys/fcntl.h +++ b/sys/sys/fcntl.h @@ -143,6 +143,7 @@ typedef __pid_t pid_t; #define O_DSYNC 0x01000000 /* POSIX data sync */ #if __BSD_VISIBLE #define O_EMPTY_PATH 0x02000000 +#define O_RESOLVE_NO_SYMLINKS 0x04000000 #endif /* diff --git a/sys/sys/namei.h b/sys/sys/namei.h index d22864a3c2c88..3388e149c4c4d 100644 --- a/sys/sys/namei.h +++ b/sys/sys/namei.h @@ -155,6 +155,7 @@ int cache_fplookup(struct nameidata *ndp, enum cache_fpl_status *status, #define LOCKSHARED 0x0100 /* Shared lock leaf */ #define NOFOLLOW 0x0000 /* do not follow symbolic links (pseudo) */ #define RBENEATH 0x100000000ULL /* No escape, even tmp, from start dir */ +#define RNOSYMLINK 0x200000000ULL /* Do not follow any symbolic links */ #define MODMASK 0xf000001ffULL /* mask of operational modifiers */ /*