Index: sys/kern/vfs_lookup.c =================================================================== --- sys/kern/vfs_lookup.c +++ sys/kern/vfs_lookup.c @@ -86,6 +86,9 @@ ndp->ni_cnd.cn_flags |= ISRESTARTED; \ } while (0) +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"); @@ -1330,6 +1333,11 @@ 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; Index: sys/kern/vfs_vnops.c =================================================================== --- sys/kern/vfs_vnops.c +++ sys/kern/vfs_vnops.c @@ -200,6 +200,8 @@ 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 ((fmode & FREAD) != 0) Index: sys/sys/fcntl.h =================================================================== --- sys/sys/fcntl.h +++ sys/sys/fcntl.h @@ -140,6 +140,7 @@ #define O_DSYNC 0x01000000 /* POSIX data sync */ #if __BSD_VISIBLE #define O_EMPTY_PATH 0x02000000 +#define O_RESOLVE_NO_SYMLINKS 0x04000000 #endif /* Index: sys/sys/namei.h =================================================================== --- sys/sys/namei.h +++ sys/sys/namei.h @@ -150,6 +150,7 @@ #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 */ /*