Date: Sun, 11 Nov 2018 00:04:36 +0000 (UTC) From: Konstantin Belousov <kib@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r340343 - in head/sys: kern sys Message-ID: <201811110004.wAB04aWF068147@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: kib Date: Sun Nov 11 00:04:36 2018 New Revision: 340343 URL: https://svnweb.freebsd.org/changeset/base/340343 Log: Allow absolute paths for O_BENEATH. The path must have a tail which does not escape starting/topping directory. The documentation will come shortly, see the man pages commit message for the reason of separate commit. Reviewed by: jilles (previous version) Discussed with: emaste Tested by: pho Sponsored by: The FreeBSD Foundation MFC after: 1 week Differential revision: https://reviews.freebsd.org/D17714 Modified: head/sys/kern/vfs_lookup.c head/sys/sys/namei.h Modified: head/sys/kern/vfs_lookup.c ============================================================================== --- head/sys/kern/vfs_lookup.c Sat Nov 10 23:49:01 2018 (r340342) +++ head/sys/kern/vfs_lookup.c Sun Nov 11 00:04:36 2018 (r340343) @@ -177,6 +177,13 @@ nameicap_tracker_add(struct nameidata *ndp, struct vno 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) { + MPASS((ndp->ni_lcf & NI_LCF_LATCH) != 0); + if (dp != ndp->ni_beneath_latch) + return; + ndp->ni_lcf |= NI_LCF_BENEATH_LATCHED; + } nt = uma_zalloc(nt_zone, M_WAITOK); vhold(dp); nt->dp = dp; @@ -184,7 +191,7 @@ nameicap_tracker_add(struct nameidata *ndp, struct vno } static void -nameicap_cleanup(struct nameidata *ndp) +nameicap_cleanup(struct nameidata *ndp, bool clean_latch) { struct nameicap_tracker *nt, *nt1; @@ -195,6 +202,8 @@ nameicap_cleanup(struct nameidata *ndp) vdrop(nt->dp); uma_zfree(nt_zone, nt); } + if (clean_latch && (ndp->ni_lcf & NI_LCF_LATCH) != 0) + vrele(ndp->ni_beneath_latch); } /* @@ -222,6 +231,11 @@ nameicap_check_dotdot(struct nameidata *ndp, struct vn 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); } @@ -242,14 +256,18 @@ namei_handle_root(struct nameidata *ndp, struct vnode struct componentname *cnp; cnp = &ndp->ni_cnd; - if ((ndp->ni_lcf & NI_LCF_STRICTRELATIVE) != 0 || - (cnp->cn_flags & BENEATH) != 0) { + if ((ndp->ni_lcf & NI_LCF_STRICTRELATIVE) != 0) { #ifdef KTRACE if (KTRPOINT(curthread, KTR_CAPFAIL)) ktrcapfail(CAPFAIL_LOOKUP, NULL, NULL); #endif return (ENOTCAPABLE); } + if ((cnp->cn_flags & BENEATH) != 0) { + ndp->ni_lcf |= NI_LCF_BENEATH_ABS; + ndp->ni_lcf &= ~NI_LCF_BENEATH_LATCHED; + nameicap_cleanup(ndp, false); + } while (*(cnp->cn_nameptr) == '/') { cnp->cn_nameptr++; ndp->ni_pathlen--; @@ -290,6 +308,7 @@ namei(struct nameidata *ndp) struct thread *td; struct proc *p; cap_rights_t rights; + struct filecaps dirfd_caps; struct uio auio; int error, linklen, startdir_used; @@ -427,6 +446,23 @@ namei(struct nameidata *ndp) if (error == 0 && dp->v_type != VDIR) error = ENOTDIR; } + if (error == 0 && (ndp->ni_lcf & NI_LCF_BENEATH_ABS) != 0) { + if (ndp->ni_dirfd == AT_FDCWD) { + ndp->ni_beneath_latch = fdp->fd_cdir; + vrefact(ndp->ni_beneath_latch); + } else { + rights = ndp->ni_rightsneeded; + cap_rights_set(&rights, CAP_LOOKUP); + error = fgetvp_rights(td, ndp->ni_dirfd, &rights, + &dirfd_caps, &ndp->ni_beneath_latch); + if (error == 0 && dp->v_type != VDIR) { + vrele(ndp->ni_beneath_latch); + error = ENOTDIR; + } + } + if (error == 0) + ndp->ni_lcf |= NI_LCF_LATCH; + } FILEDESC_SUNLOCK(fdp); if (ndp->ni_startdir != NULL && !startdir_used) vrele(ndp->ni_startdir); @@ -456,9 +492,15 @@ namei(struct nameidata *ndp) namei_cleanup_cnp(cnp); } else cnp->cn_flags |= HASBUF; - nameicap_cleanup(ndp); - SDT_PROBE2(vfs, namei, lookup, return, 0, ndp->ni_vp); - return (0); + if ((ndp->ni_lcf & (NI_LCF_BENEATH_ABS | + NI_LCF_BENEATH_LATCHED)) == NI_LCF_BENEATH_ABS) { + NDFREE(ndp, 0); + error = ENOTCAPABLE; + } + nameicap_cleanup(ndp, true); + SDT_PROBE2(vfs, namei, lookup, return, error, + (error == 0 ? ndp->ni_vp : NULL)); + return (error); } if (ndp->ni_loopcnt++ >= MAXSYMLINKS) { error = ELOOP; @@ -529,8 +571,9 @@ namei(struct nameidata *ndp) vrele(ndp->ni_dvp); out: vrele(ndp->ni_rootdir); + MPASS(error != 0); namei_cleanup_cnp(cnp); - nameicap_cleanup(ndp); + nameicap_cleanup(ndp, true); SDT_PROBE2(vfs, namei, lookup, return, error, NULL); return (error); } Modified: head/sys/sys/namei.h ============================================================================== --- head/sys/sys/namei.h Sat Nov 10 23:49:01 2018 (r340342) +++ head/sys/sys/namei.h Sun Nov 11 00:04:36 2018 (r340343) @@ -100,6 +100,7 @@ struct nameidata { */ struct componentname ni_cnd; struct nameicap_tracker_head ni_cap_tracker; + struct vnode *ni_beneath_latch; }; #ifdef _KERNEL @@ -163,6 +164,9 @@ struct nameidata { */ #define NI_LCF_STRICTRELATIVE 0x0001 /* relative lookup only */ #define NI_LCF_CAP_DOTDOT 0x0002 /* ".." in strictrelative case */ +#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 */ /* * Initialization of a nameidata structure.
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201811110004.wAB04aWF068147>