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
This commit is contained in:
parent
71ec454d66
commit
ade85c5eec
@ -177,6 +177,13 @@ nameicap_tracker_add(struct nameidata *ndp, struct vnode *dp)
|
||||
|
||||
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 vnode *dp)
|
||||
}
|
||||
|
||||
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 vnode *dp)
|
||||
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 **dpp)
|
||||
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);
|
||||
}
|
||||
|
@ -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.
|
||||
|
Loading…
Reference in New Issue
Block a user