svn commit: r340343 - in head/sys: kern sys
Konstantin Belousov
kib at FreeBSD.org
Sun Nov 11 00:04:37 UTC 2018
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.
More information about the svn-src-all
mailing list