diff --git a/sys/kern/vfs_lookup.c b/sys/kern/vfs_lookup.c --- a/sys/kern/vfs_lookup.c +++ b/sys/kern/vfs_lookup.c @@ -182,8 +182,8 @@ if ((ndp->ni_lcf & NI_LCF_CAP_DOTDOT) == 0 || dp->v_type != VDIR) return; cnp = &ndp->ni_cnd; - if ((cnp->cn_flags & BENEATH) != 0 && - (ndp->ni_lcf & NI_LCF_BENEATH_LATCHED) == 0) { + if ((ndp->ni_lcf & (NI_LCF_OPER_BENEATH | NI_LCF_BENEATH_LATCHED)) == + NI_LCF_OPER_BENEATH) { MPASS((ndp->ni_lcf & NI_LCF_LATCH) != 0); if (dp != ndp->ni_beneath_latch) return; @@ -276,7 +276,7 @@ #endif return (ENOTCAPABLE); } - if ((cnp->cn_flags & BENEATH) != 0) { + if ((ndp->ni_lcf & NI_LCF_OPER_BENEATH) != 0) { ndp->ni_lcf |= NI_LCF_BENEATH_ABS; ndp->ni_lcf &= ~NI_LCF_BENEATH_LATCHED; nameicap_cleanup(ndp, false); @@ -309,6 +309,11 @@ *pwdp = NULL; *dpp = NULL; + if ((cnp->cn_flags & RBENEATH) != 0) + ndp->ni_lcf |= NI_LCF_OPER_RBENEATH; + else if ((cnp->cn_flags & BENEATH) != 0) + ndp->ni_lcf |= NI_LCF_OPER_BENEATH; + #ifdef CAPABILITY_MODE /* * In capability mode, lookups must be restricted to happen in @@ -324,6 +329,10 @@ * the relative root. */ if (IN_CAPABILITY_MODE(td) && (cnp->cn_flags & NOCAPCHECK) == 0) { + if ((ndp->ni_lcf & NI_LCF_OPER_BENEATH) != 0) { + ndp->ni_lcf &= ~NI_LCF_OPER_BENEATH; + ndp->ni_lcf |= NI_LCF_OPER_RBENEATH; + } ndp->ni_lcf |= NI_LCF_STRICTRELATIVE; ndp->ni_resflags |= NIRES_STRICTREL; if (ndp->ni_dirfd == AT_FDCWD) { @@ -411,7 +420,7 @@ if (error == 0 && (*dpp)->v_type != VDIR) error = ENOTDIR; } - if (error == 0 && (cnp->cn_flags & BENEATH) != 0) { + if (error == 0 && (ndp->ni_lcf & NI_LCF_OPER_BENEATH) != 0) { if (ndp->ni_dirfd == AT_FDCWD) { ndp->ni_beneath_latch = pwd->pwd_cdir; vrefact(ndp->ni_beneath_latch); @@ -428,7 +437,7 @@ if (error == 0) ndp->ni_lcf |= NI_LCF_LATCH; } - if (error == 0 && (cnp->cn_flags & RBENEATH) != 0) { + if (error == 0 && (ndp->ni_lcf & NI_LCF_OPER_RBENEATH) != 0) { if (cnp->cn_pnbuf[0] == '/' || (ndp->ni_lcf & NI_LCF_BENEATH_ABS) != 0) { error = EINVAL; @@ -457,8 +466,8 @@ NI_LCF_BENEATH_ABS); if (((ndp->ni_lcf & NI_LCF_STRICTRELATIVE) != 0 && lookup_cap_dotdot != 0) || - ((ndp->ni_lcf & NI_LCF_STRICTRELATIVE) == 0 && - (cnp->cn_flags & BENEATH) != 0)) + (ndp->ni_lcf & (NI_LCF_STRICTRELATIVE | NI_LCF_OPER_BENEATH)) == + NI_LCF_OPER_BENEATH) ndp->ni_lcf |= NI_LCF_CAP_DOTDOT; SDT_PROBE4(vfs, namei, lookup, entry, *dpp, cnp->cn_pnbuf, cnp->cn_flags, false); diff --git a/sys/sys/namei.h b/sys/sys/namei.h --- a/sys/sys/namei.h +++ b/sys/sys/namei.h @@ -209,6 +209,8 @@ #define NI_LCF_BENEATH_ABS 0x0004 /* BENEATH with absolute path */ #define NI_LCF_BENEATH_LATCHED 0x0008 /* BENEATH_ABS traversed starting dir */ #define NI_LCF_LATCH 0x0010 /* ni_beneath_latch valid */ +#define NI_LCF_OPER_BENEATH 0x0020 /* operate as if BENEATH specified */ +#define NI_LCF_OPER_RBENEATH 0x0040 /* operate as if RENEATH specified */ /* * Initialization of a nameidata structure.