Index: lib/libc/sys/access.2 =================================================================== --- lib/libc/sys/access.2 +++ lib/libc/sys/access.2 @@ -127,6 +127,13 @@ flag in the .Xr open 2 manual page. +.It Dv AT_RELATIVE_BENEATH +Only walks paths below the topping directory. +See the description of the +.Dv O_RELATIVE_BENEATH +flag in the +.Xr open 2 +manual page. .El .Pp Even if a process's real or effective user has appropriate privileges Index: lib/libc/sys/chflags.2 =================================================================== --- lib/libc/sys/chflags.2 +++ lib/libc/sys/chflags.2 @@ -102,6 +102,13 @@ flag in the .Xr open 2 manual page. +.It Dv AT_RELATIVE_BENEATH +Only walks paths below the topping directory. +See the description of the +.Dv O_RELATIVE_BENEATH +flag in the +.Xr open 2 +manual page. .El .Pp If Index: lib/libc/sys/chmod.2 =================================================================== --- lib/libc/sys/chmod.2 +++ lib/libc/sys/chmod.2 @@ -109,6 +109,13 @@ flag in the .Xr open 2 manual page. +.It Dv AT_RELATIVE_BENEATH +Only walks paths below the topping directory. +See the description of the +.Dv O_RELATIVE_BENEATH +flag in the +.Xr open 2 +manual page. .El .Pp If Index: lib/libc/sys/chown.2 =================================================================== --- lib/libc/sys/chown.2 +++ lib/libc/sys/chown.2 @@ -126,6 +126,13 @@ flag in the .Xr open 2 manual page. +.It Dv AT_RELATIVE_BENEATH +Only walks paths below the topping directory. +See the description of the +.Dv O_RELATIVE_BENEATH +flag in the +.Xr open 2 +manual page. .El .Pp If Index: lib/libc/sys/fhlink.2 =================================================================== --- lib/libc/sys/fhlink.2 +++ lib/libc/sys/fhlink.2 @@ -113,6 +113,13 @@ flag in the .Xr open 2 manual page. +.It Dv AT_RELATIVE_BENEATH +Only walks paths below the topping directory. +See the description of the +.Dv O_RELATIVE_BENEATH +flag in the +.Xr open 2 +manual page. .El .Pp If Index: lib/libc/sys/getfh.2 =================================================================== --- lib/libc/sys/getfh.2 +++ lib/libc/sys/getfh.2 @@ -112,6 +112,13 @@ flag in the .Xr open 2 manual page. +.It Dv AT_RELATIVE_BENEATH +Only walks paths below the topping directory. +See the description of the +.Dv O_RELATIVE_BENEATH +flag in the +.Xr open 2 +manual page. .El .Pp If Index: lib/libc/sys/link.2 =================================================================== --- lib/libc/sys/link.2 +++ lib/libc/sys/link.2 @@ -122,6 +122,13 @@ flag in the .Xr open 2 manual page. +.It Dv AT_RELATIVE_BENEATH +Only walks paths below the topping directory. +See the description of the +.Dv O_RELATIVE_BENEATH +flag in the +.Xr open 2 +manual page. .El .Pp If Index: lib/libc/sys/open.2 =================================================================== --- lib/libc/sys/open.2 +++ lib/libc/sys/open.2 @@ -117,6 +117,12 @@ a directory passed by the .Fa fd argument is used as the topping point for the resolution. +When +.Dv O_BENEATH +is specified with a relative path, the +.Fa fd +argument is used both as the starting point, and as the topping point +for the resolution. See the definition of the .Dv O_BENEATH flag below. @@ -183,7 +189,8 @@ O_DIRECTORY error if file is not a directory O_CLOEXEC set FD_CLOEXEC upon open O_VERIFY verify the contents of the file -O_BENEATH require path to be strictly relative to topping directory +O_BENEATH require resolved path to be strictly relative to topping directory +O_RELATIVE_BENEATH require walked path to be strictly relative to topping directory .Ed .Pp Opening a file with @@ -311,8 +318,8 @@ .Dv O_BENEATH returns .Er ENOTCAPABLE -if the specified relative path, after resolving all symlinks and ".." -references, does not reside in the directory hierarchy of +if the specified path, after resolving all symlinks and ".." +references, does not end up with tail residing in the directory hierarchy of children beneath the topping directory. Topping directory is the process current directory if relative .Fa path @@ -322,11 +329,20 @@ .Fa fd argument when using .Fn openat . -If the specified path is absolute, .Dv O_BENEATH allows arbitrary prefix that ends up at the topping directory, after which all further resolved components must be under it. .Pp +.Dv O_RELATIVE_BENEATH +returns +.Er ENOTCAPABLE +if any intermediate component of the specified relative path does not +reside in the directory hierarchy beneath the topping directory. +Comparing to +.Dv O_BENEATH, +absolute paths or even the temporal escape from beneath of the topping +directory is not allowed. +.Pp When .Fa fd is opened with @@ -540,6 +556,12 @@ .Dv O_EXEC or .Dv O_SEARCH . +.It Bq Er EINVAL +The +.Dv O_RELATIVE_BENEATH +flag is specified and +.Dv path +is absolute. .It Bq Er EBADF The .Fa path @@ -582,6 +604,12 @@ or the relative .Fa path escapes it. +.It Bq Er ENOTCAPABLE +The +.Dv O_RELATIVE_BENEATH +flag was provided, and the relative +.Fa path +escapes topping directory. .El .Sh SEE ALSO .Xr chmod 2 , Index: lib/libc/sys/stat.2 =================================================================== --- lib/libc/sys/stat.2 +++ lib/libc/sys/stat.2 @@ -120,6 +120,13 @@ flag in the .Xr open 2 manual page. +.It Dv AT_RELATIVE_BENEATH +Only walks paths below the topping directory. +See the description of the +.Dv O_RELATIVE_BENEATH +flag in the +.Xr open 2 +manual page. .El .Pp If Index: lib/libc/sys/unlink.2 =================================================================== --- lib/libc/sys/unlink.2 +++ lib/libc/sys/unlink.2 @@ -100,6 +100,13 @@ flag in the .Xr open 2 manual page. +.It Dv AT_RELATIVE_BENEATH +Only walks paths below the topping directory. +See the description of the +.Dv O_RELATIVE_BENEATH +flag in the +.Xr open 2 +manual page. .El .Pp If Index: lib/libc/sys/utimensat.2 =================================================================== --- lib/libc/sys/utimensat.2 +++ lib/libc/sys/utimensat.2 @@ -154,6 +154,13 @@ flag in the .Xr open 2 manual page. +.It Dv AT_RELATIVE_BENEATH +Only walks paths below the topping directory. +See the description of the +.Dv O_RELATIVE_BENEATH +flag in the +.Xr open 2 +manual page. .El .Sh RETURN VALUES .Rv -std Index: sys/kern/vfs_lookup.c =================================================================== --- sys/kern/vfs_lookup.c +++ sys/kern/vfs_lookup.c @@ -178,11 +178,13 @@ nameicap_tracker_add(struct nameidata *ndp, struct vnode *dp) { struct nameicap_tracker *nt; + struct componentname *cnp; if ((ndp->ni_lcf & NI_LCF_CAP_DOTDOT) == 0 || dp->v_type != VDIR) return; - if ((ndp->ni_lcf & (NI_LCF_BENEATH_ABS | NI_LCF_BENEATH_LATCHED)) == - NI_LCF_BENEATH_ABS) { + cnp = &ndp->ni_cnd; + if ((cnp->cn_flags & BENEATH) != 0 && + (ndp->ni_lcf & NI_LCF_BENEATH_LATCHED) == 0) { MPASS((ndp->ni_lcf & NI_LCF_LATCH) != 0); if (dp != ndp->ni_beneath_latch) return; @@ -215,7 +217,11 @@ /* * For dotdot lookups in capability mode, only allow the component * lookup to succeed if the resulting directory was already traversed - * during the operation. Also fail dotdot lookups for non-local + * during the operation. This catches situations where already + * traversed directory is moved to different parent, and then we walk + * over it with dotdots. + * + * Also allow to force failure of dotdot lookups for non-local * filesystems, where external agents might assist local lookups to * escape the compartment. */ @@ -234,14 +240,15 @@ return (ENOTCAPABLE); TAILQ_FOREACH_REVERSE(nt, &ndp->ni_cap_tracker, nameicap_tracker_head, nm_link) { + if ((ndp->ni_lcf & NI_LCF_LATCH) != 0 && + ndp->ni_beneath_latch == nt->dp) { + ndp->ni_lcf &= ~NI_LCF_BENEATH_LATCHED; + nameicap_cleanup(ndp, false); + return (0); + } if (dp == nt->dp) return (0); } - if ((ndp->ni_lcf & NI_LCF_BENEATH_ABS) != 0) { - ndp->ni_lcf &= ~NI_LCF_BENEATH_LATCHED; - nameicap_cleanup(ndp, false); - return (0); - } return (ENOTCAPABLE); } @@ -318,6 +325,7 @@ */ if (IN_CAPABILITY_MODE(td) && (cnp->cn_flags & NOCAPCHECK) == 0) { ndp->ni_lcf |= NI_LCF_STRICTRELATIVE; + ndp->ni_resflags |= NIRES_STRICTREL; if (ndp->ni_dirfd == AT_FDCWD) { #ifdef KTRACE if (KTRPOINT(td, KTR_CAPFAIL)) @@ -396,6 +404,7 @@ ndp->ni_filecaps.fc_fcntls != CAP_FCNTL_ALL || ndp->ni_filecaps.fc_nioctls != -1) { ndp->ni_lcf |= NI_LCF_STRICTRELATIVE; + ndp->ni_resflags |= NIRES_STRICTREL; } #endif } @@ -419,6 +428,16 @@ if (error == 0) ndp->ni_lcf |= NI_LCF_LATCH; } + if (error == 0 && (cnp->cn_flags & RBENEATH) != 0) { + if (cnp->cn_pnbuf[0] == '/' || + (ndp->ni_lcf & NI_LCF_BENEATH_ABS) != 0) { + error = EINVAL; + } else if ((ndp->ni_lcf & NI_LCF_STRICTRELATIVE) == 0) { + ndp->ni_lcf |= NI_LCF_STRICTRELATIVE | + NI_LCF_CAP_DOTDOT; + } + } + /* * If we are auditing the kernel pathname, save the user pathname. */ @@ -586,8 +605,8 @@ namei_cleanup_cnp(cnp); } else cnp->cn_flags |= HASBUF; - if ((ndp->ni_lcf & (NI_LCF_BENEATH_ABS | - NI_LCF_BENEATH_LATCHED)) == NI_LCF_BENEATH_ABS) { + if ((ndp->ni_lcf & (NI_LCF_LATCH | + NI_LCF_BENEATH_LATCHED)) == NI_LCF_LATCH) { NDFREE(ndp, 0); error = ENOTCAPABLE; } Index: sys/kern/vfs_syscalls.c =================================================================== --- sys/kern/vfs_syscalls.c +++ sys/kern/vfs_syscalls.c @@ -112,6 +112,26 @@ static int kern_linkat_vp(struct thread *td, struct vnode *vp, int fd, const char *path, enum uio_seg segflag); +static uint64_t +at2cnpflags(u_int at_flags, u_int mask) +{ + u_int64_t res; + + res = 0; + at_flags &= mask; + if ((at_flags & AT_BENEATH) != 0) + res |= BENEATH; + if ((at_flags & AT_RESOLVE_BENEATH) != 0) + res |= RBENEATH; + /* FOLLOW is pseudo flag */ + if ((at_flags & AT_SYMLINK_NOFOLLOW) != 0) + res |= NOFOLLOW; + if ((mask & AT_SYMLINK_FOLLOW) != 0 && + (at_flags & AT_SYMLINK_FOLLOW) == 0) + res |= NOFOLLOW; + return (res); +} + int kern_sync(struct thread *td) { @@ -1136,7 +1156,7 @@ * understand exactly what would happen, and we don't think * that it ever should. */ - if ((nd.ni_lcf & NI_LCF_STRICTRELATIVE) == 0 && + if ((nd.ni_resflags & NIRES_STRICTREL) == 0 && (error == ENODEV || error == ENXIO) && td->td_dupfd >= 0) { error = dupfdopen(td, fdp, td->td_dupfd, flags, error, @@ -1183,7 +1203,7 @@ struct filecaps *fcaps; #ifdef CAPABILITIES - if ((nd.ni_lcf & NI_LCF_STRICTRELATIVE) != 0) + if ((nd.ni_resflags & NIRES_STRICTREL) != 0) fcaps = &nd.ni_filecaps; else #endif @@ -1484,12 +1504,13 @@ int flag; flag = uap->flag; - if ((flag & ~(AT_SYMLINK_FOLLOW | AT_BENEATH)) != 0) + if ((flag & ~(AT_SYMLINK_FOLLOW | AT_BENEATH | + AT_RESOLVE_BENEATH)) != 0) return (EINVAL); return (kern_linkat(td, uap->fd1, uap->fd2, uap->path1, uap->path2, - UIO_USERSPACE, ((flag & AT_SYMLINK_FOLLOW) != 0 ? FOLLOW : - NOFOLLOW) | ((flag & AT_BENEATH) != 0 ? BENEATH : 0))); + UIO_USERSPACE, at2cnpflags(flag, AT_SYMLINK_FOLLOW | AT_BENEATH | + AT_RESOLVE_BENEATH))); } int hardlink_check_uid = 0; @@ -1854,7 +1875,7 @@ restart: bwillwrite(); NDINIT_ATRIGHTS(&nd, DELETE, LOCKPARENT | LOCKLEAF | AUDITVNODE1 | - ((flag & AT_BENEATH) != 0 ? BENEATH : 0), + at2cnpflags(flag, AT_BENEATH | AT_RESOLVE_BENEATH), pathseg, path, dfd, &cap_unlinkat_rights, td); if ((error = namei(&nd)) != 0) { if (error == EINVAL) @@ -2057,7 +2078,7 @@ struct nameidata nd; int error; - if ((flag & ~(AT_EACCESS | AT_BENEATH)) != 0) + if ((flag & ~(AT_EACCESS | AT_BENEATH | AT_RESOLVE_BENEATH)) != 0) return (EINVAL); if (amode != F_OK && (amode & ~(R_OK | W_OK | X_OK)) != 0) return (EINVAL); @@ -2078,7 +2099,7 @@ usecred = cred; AUDIT_ARG_VALUE(amode); NDINIT_ATRIGHTS(&nd, LOOKUP, FOLLOW | LOCKSHARED | LOCKLEAF | - AUDITVNODE1 | ((flag & AT_BENEATH) != 0 ? BENEATH : 0), + AUDITVNODE1 | at2cnpflags(flag, AT_BENEATH | AT_RESOLVE_BENEATH), pathseg, path, fd, &cap_fstat_rights, td); if ((error = namei(&nd)) != 0) goto out; @@ -2369,13 +2390,13 @@ struct nameidata nd; int error; - if ((flag & ~(AT_SYMLINK_NOFOLLOW | AT_BENEATH)) != 0) + if ((flag & ~(AT_SYMLINK_NOFOLLOW | AT_BENEATH | + AT_RESOLVE_BENEATH)) != 0) return (EINVAL); - NDINIT_ATRIGHTS(&nd, LOOKUP, ((flag & AT_SYMLINK_NOFOLLOW) != 0 ? - NOFOLLOW : FOLLOW) | ((flag & AT_BENEATH) != 0 ? BENEATH : 0) | - LOCKSHARED | LOCKLEAF | AUDITVNODE1, pathseg, path, fd, - &cap_fstat_rights, td); + NDINIT_ATRIGHTS(&nd, LOOKUP, at2cnpflags(flag, AT_BENEATH | + AT_RESOLVE_BENEATH | AT_SYMLINK_NOFOLLOW) | LOCKSHARED | LOCKLEAF | + AUDITVNODE1, pathseg, path, fd, &cap_fstat_rights, td); if ((error = namei(&nd)) != 0) return (error); @@ -2693,7 +2714,8 @@ sys_chflagsat(struct thread *td, struct chflagsat_args *uap) { - if ((uap->atflag & ~(AT_SYMLINK_NOFOLLOW | AT_BENEATH)) != 0) + if ((uap->atflag & ~(AT_SYMLINK_NOFOLLOW | AT_BENEATH | + AT_RESOLVE_BENEATH)) != 0) return (EINVAL); return (kern_chflagsat(td, uap->fd, uap->path, UIO_USERSPACE, @@ -2722,12 +2744,11 @@ enum uio_seg pathseg, u_long flags, int atflag) { struct nameidata nd; - int error, follow; + int error; AUDIT_ARG_FFLAGS(flags); - follow = (atflag & AT_SYMLINK_NOFOLLOW) ? NOFOLLOW : FOLLOW; - follow |= (atflag & AT_BENEATH) != 0 ? BENEATH : 0; - NDINIT_ATRIGHTS(&nd, LOOKUP, follow | AUDITVNODE1, pathseg, path, fd, + NDINIT_ATRIGHTS(&nd, LOOKUP, at2cnpflags(atflag, AT_SYMLINK_NOFOLLOW | + AT_BENEATH | AT_RESOLVE_BENEATH) | AUDITVNODE1, pathseg, path, fd, &cap_fchflags_rights, td); if ((error = namei(&nd)) != 0) return (error); @@ -2822,7 +2843,8 @@ sys_fchmodat(struct thread *td, struct fchmodat_args *uap) { - if ((uap->flag & ~(AT_SYMLINK_NOFOLLOW | AT_BENEATH)) != 0) + if ((uap->flag & ~(AT_SYMLINK_NOFOLLOW | AT_BENEATH | + AT_RESOLVE_BENEATH)) != 0) return (EINVAL); return (kern_fchmodat(td, uap->fd, uap->path, UIO_USERSPACE, @@ -2851,12 +2873,11 @@ enum uio_seg pathseg, mode_t mode, int flag) { struct nameidata nd; - int error, follow; + int error; AUDIT_ARG_MODE(mode); - follow = (flag & AT_SYMLINK_NOFOLLOW) != 0 ? NOFOLLOW : FOLLOW; - follow |= (flag & AT_BENEATH) != 0 ? BENEATH : 0; - NDINIT_ATRIGHTS(&nd, LOOKUP, follow | AUDITVNODE1, pathseg, path, fd, + NDINIT_ATRIGHTS(&nd, LOOKUP, at2cnpflags(flag, AT_SYMLINK_NOFOLLOW | + AT_BENEATH | AT_RESOLVE_BENEATH) | AUDITVNODE1, pathseg, path, fd, &cap_fchmod_rights, td); if ((error = namei(&nd)) != 0) return (error); @@ -2951,7 +2972,8 @@ sys_fchownat(struct thread *td, struct fchownat_args *uap) { - if ((uap->flag & ~(AT_SYMLINK_NOFOLLOW | AT_BENEATH)) != 0) + if ((uap->flag & ~(AT_SYMLINK_NOFOLLOW | AT_BENEATH | + AT_RESOLVE_BENEATH)) != 0) return (EINVAL); return (kern_fchownat(td, uap->fd, uap->path, UIO_USERSPACE, uap->uid, @@ -2963,12 +2985,11 @@ enum uio_seg pathseg, int uid, int gid, int flag) { struct nameidata nd; - int error, follow; + int error; AUDIT_ARG_OWNER(uid, gid); - follow = (flag & AT_SYMLINK_NOFOLLOW) ? NOFOLLOW : FOLLOW; - follow |= (flag & AT_BENEATH) != 0 ? BENEATH : 0; - NDINIT_ATRIGHTS(&nd, LOOKUP, follow | AUDITVNODE1, pathseg, path, fd, + NDINIT_ATRIGHTS(&nd, LOOKUP, at2cnpflags(flag, AT_SYMLINK_NOFOLLOW | + AT_BENEATH | AT_RESOLVE_BENEATH) | AUDITVNODE1, pathseg, path, fd, &cap_fchown_rights, td); if ((error = namei(&nd)) != 0) @@ -3320,13 +3341,14 @@ struct timespec ts[2]; int error, flags; - if ((flag & ~(AT_SYMLINK_NOFOLLOW | AT_BENEATH)) != 0) + if ((flag & ~(AT_SYMLINK_NOFOLLOW | AT_BENEATH | + AT_RESOLVE_BENEATH)) != 0) return (EINVAL); if ((error = getutimens(tptr, tptrseg, ts, &flags)) != 0) return (error); - NDINIT_ATRIGHTS(&nd, LOOKUP, ((flag & AT_SYMLINK_NOFOLLOW) ? NOFOLLOW : - FOLLOW) | ((flag & AT_BENEATH) != 0 ? BENEATH : 0) | AUDITVNODE1, + NDINIT_ATRIGHTS(&nd, LOOKUP, at2cnpflags(flag, AT_SYMLINK_NOFOLLOW | + AT_BENEATH | AT_RESOLVE_BENEATH) | AUDITVNODE1, pathseg, path, fd, &cap_futimes_rights, td); if ((error = namei(&nd)) != 0) return (error); @@ -3821,7 +3843,7 @@ restart: bwillwrite(); NDINIT_ATRIGHTS(&nd, DELETE, LOCKPARENT | LOCKLEAF | AUDITVNODE1 | - ((flag & AT_BENEATH) != 0 ? BENEATH : 0), + at2cnpflags(flag, AT_BENEATH | AT_RESOLVE_BENEATH), pathseg, path, dfd, &cap_unlinkat_rights, td); if ((error = namei(&nd)) != 0) goto fdout; @@ -4307,7 +4329,8 @@ sys_getfhat(struct thread *td, struct getfhat_args *uap) { - if ((uap->flags & ~(AT_SYMLINK_NOFOLLOW | AT_BENEATH)) != 0) + if ((uap->flags & ~(AT_SYMLINK_NOFOLLOW | AT_BENEATH | + AT_RESOLVE_BENEATH)) != 0) return (EINVAL); return (kern_getfhat(td, uap->flags, uap->fd, uap->path, UIO_USERSPACE, uap->fhp)); @@ -4325,9 +4348,9 @@ error = priv_check(td, PRIV_VFS_GETFH); if (error != 0) return (error); - NDINIT_AT(&nd, LOOKUP, ((flags & AT_SYMLINK_NOFOLLOW) != 0 ? NOFOLLOW : - FOLLOW) | ((flags & AT_BENEATH) != 0 ? BENEATH : 0) | LOCKLEAF | - AUDITVNODE1, pathseg, path, fd, td); + NDINIT_AT(&nd, LOOKUP, at2cnpflags(flags, AT_SYMLINK_NOFOLLOW | + AT_BENEATH | AT_RESOLVE_BENEATH) | LOCKLEAF | AUDITVNODE1, + pathseg, path, fd, td); error = namei(&nd); if (error != 0) return (error); Index: sys/kern/vfs_vnops.c =================================================================== --- sys/kern/vfs_vnops.c +++ sys/kern/vfs_vnops.c @@ -192,6 +192,23 @@ return (vn_open_cred(ndp, flagp, cmode, 0, td->td_ucred, fp)); } +static uint64_t +open2nameif(int fmode, u_int vn_open_flags) +{ + uint64_t res; + + res = ISOPEN | LOCKLEAF; + if ((fmode & O_BENEATH) != 0) + res |= BENEATH; + if ((fmode & O_RESOLVE_BENEATH) != 0) + res |= RBENEATH; + if ((vn_open_flags & VN_OPEN_NOAUDIT) == 0) + res |= AUDITVNODE1; + if ((vn_open_flags & VN_OPEN_NOCAPCHECK) != 0) + res |= NOCAPCHECK; + return (res); +} + /* * Common code for vnode open operations via a name lookup. * Lookup the vnode and invoke VOP_CREATE if needed. @@ -218,19 +235,14 @@ return (EINVAL); else if ((fmode & (O_CREAT | O_DIRECTORY)) == O_CREAT) { ndp->ni_cnd.cn_nameiop = CREATE; + ndp->ni_cnd.cn_flags = open2nameif(fmode, vn_open_flags); /* * Set NOCACHE to avoid flushing the cache when * rolling in many files at once. */ - ndp->ni_cnd.cn_flags = ISOPEN | LOCKPARENT | LOCKLEAF | NOCACHE; + ndp->ni_cnd.cn_flags |= LOCKPARENT | NOCACHE; if ((fmode & O_EXCL) == 0 && (fmode & O_NOFOLLOW) == 0) ndp->ni_cnd.cn_flags |= FOLLOW; - if ((fmode & O_BENEATH) != 0) - ndp->ni_cnd.cn_flags |= BENEATH; - if (!(vn_open_flags & VN_OPEN_NOAUDIT)) - ndp->ni_cnd.cn_flags |= AUDITVNODE1; - if (vn_open_flags & VN_OPEN_NOCAPCHECK) - ndp->ni_cnd.cn_flags |= NOCAPCHECK; if ((vn_open_flags & VN_OPEN_INVFS) == 0) bwillwrite(); if ((error = namei(ndp)) != 0) @@ -285,16 +297,11 @@ } } else { ndp->ni_cnd.cn_nameiop = LOOKUP; - ndp->ni_cnd.cn_flags = ISOPEN | - ((fmode & O_NOFOLLOW) ? NOFOLLOW : FOLLOW) | LOCKLEAF; - if (!(fmode & FWRITE)) + ndp->ni_cnd.cn_flags = open2nameif(fmode, vn_open_flags); + ndp->ni_cnd.cn_flags |= (fmode & O_NOFOLLOW) != 0 ? NOFOLLOW : + FOLLOW; + if ((fmode & FWRITE) == 0) ndp->ni_cnd.cn_flags |= LOCKSHARED; - if ((fmode & O_BENEATH) != 0) - ndp->ni_cnd.cn_flags |= BENEATH; - if (!(vn_open_flags & VN_OPEN_NOAUDIT)) - ndp->ni_cnd.cn_flags |= AUDITVNODE1; - if (vn_open_flags & VN_OPEN_NOCAPCHECK) - ndp->ni_cnd.cn_flags |= NOCAPCHECK; if ((error = namei(ndp)) != 0) return (error); vp = ndp->ni_vp; Index: sys/sys/fcntl.h =================================================================== --- sys/sys/fcntl.h +++ sys/sys/fcntl.h @@ -136,6 +136,9 @@ #if __BSD_VISIBLE #define O_VERIFY 0x00200000 /* open only after verification */ #define O_BENEATH 0x00400000 /* Fail if not under cwd */ +#define O_RESOLVE_BENEATH 0x00800000 /* As O_BENEATH, but do not allow + resolve to walk out of cwd even to + return back */ #endif /* @@ -215,6 +218,9 @@ #define AT_SYMLINK_FOLLOW 0x0400 /* Follow symbolic link */ #define AT_REMOVEDIR 0x0800 /* Remove directory instead of file */ #define AT_BENEATH 0x1000 /* Fail if not under dirfd */ +#define AT_RESOLVE_BENEATH 0x2000 /* As AT_BENEATH, but do not allow + resolve to walk out of dirfd even + to return back */ #endif /* Index: sys/sys/namei.h =================================================================== --- sys/sys/namei.h +++ sys/sys/namei.h @@ -133,7 +133,8 @@ #define BENEATH 0x0080 /* No escape from the start dir */ #define LOCKSHARED 0x0100 /* Shared lock leaf */ #define NOFOLLOW 0x0000 /* do not follow symbolic links (pseudo) */ -#define MODMASK 0x01fc /* mask of operational modifiers */ +#define RBENEATH 0x100000000ULL /* XXX */ +#define MODMASK 0xf000001fcULL /* mask of operational modifiers */ /* * Namei parameter descriptors. * @@ -183,6 +184,7 @@ * Namei results flags */ #define NIRES_ABS 0x00000001 /* Path was absolute */ +#define NIRES_STRICTREL 0x00000002 /* Restricted lookup result */ /* * Flags in ni_lcf, valid for the duration of the namei call.