From owner-svn-src-all@freebsd.org Sun Nov 11 00:04:37 2018 Return-Path: Delivered-To: svn-src-all@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 9967A110FF15; Sun, 11 Nov 2018 00:04:37 +0000 (UTC) (envelope-from kib@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client CN "mxrelay.nyi.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 11F5F83216; Sun, 11 Nov 2018 00:04:37 +0000 (UTC) (envelope-from kib@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id E725B21D8; Sun, 11 Nov 2018 00:04:36 +0000 (UTC) (envelope-from kib@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id wAB04aYi068149; Sun, 11 Nov 2018 00:04:36 GMT (envelope-from kib@FreeBSD.org) Received: (from kib@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id wAB04aWF068147; Sun, 11 Nov 2018 00:04:36 GMT (envelope-from kib@FreeBSD.org) Message-Id: <201811110004.wAB04aWF068147@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: kib set sender to kib@FreeBSD.org using -f From: Konstantin Belousov Date: Sun, 11 Nov 2018 00:04:36 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r340343 - in head/sys: kern sys X-SVN-Group: head X-SVN-Commit-Author: kib X-SVN-Commit-Paths: in head/sys: kern sys X-SVN-Commit-Revision: 340343 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Rspamd-Queue-Id: 11F5F83216 X-Spamd-Result: default: False [-106.88 / 200.00]; ARC_NA(0.00)[]; NEURAL_HAM_MEDIUM(-1.00)[-1.000,0]; ALLOW_DOMAIN_WHITELIST(-100.00)[FreeBSD.org]; FROM_HAS_DN(0.00)[]; RCPT_COUNT_THREE(0.00)[3]; TO_MATCH_ENVRCPT_ALL(0.00)[]; NEURAL_HAM_LONG(-1.00)[-1.000,0]; MIME_GOOD(-0.10)[text/plain]; TO_DN_NONE(0.00)[]; HAS_XAW(0.00)[]; R_SPF_SOFTFAIL(0.00)[~all]; DMARC_NA(0.00)[FreeBSD.org]; RCVD_COUNT_THREE(0.00)[4]; MX_GOOD(-0.01)[cached: mx1.FreeBSD.org]; NEURAL_HAM_SHORT(-1.00)[-1.000,0]; FROM_EQ_ENVFROM(0.00)[]; R_DKIM_NA(0.00)[]; RCVD_TLS_LAST(0.00)[]; ASN(0.00)[asn:11403, ipnet:2610:1c1:1::/48, country:US]; IP_SCORE(-3.77)[ip: (-9.91), ipnet: 2610:1c1:1::/48(-4.93), asn: 11403(-3.89), country: US(-0.09)] X-Rspamd-Server: mx1.freebsd.org X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 11 Nov 2018 00:04:37 -0000 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.