Changeset View
Changeset View
Standalone View
Standalone View
sys/kern/vfs_lookup.c
| Show First 20 Lines • Show All 171 Lines • ▼ Show 20 Lines | |||||
| static void | static void | ||||
| nameicap_tracker_add(struct nameidata *ndp, struct vnode *dp) | nameicap_tracker_add(struct nameidata *ndp, struct vnode *dp) | ||||
| { | { | ||||
| struct nameicap_tracker *nt; | struct nameicap_tracker *nt; | ||||
| if ((ndp->ni_lcf & NI_LCF_CAP_DOTDOT) == 0 || dp->v_type != VDIR) | if ((ndp->ni_lcf & NI_LCF_CAP_DOTDOT) == 0 || dp->v_type != VDIR) | ||||
| return; | 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); | nt = uma_zalloc(nt_zone, M_WAITOK); | ||||
| vhold(dp); | vhold(dp); | ||||
| nt->dp = dp; | nt->dp = dp; | ||||
| TAILQ_INSERT_TAIL(&ndp->ni_cap_tracker, nt, nm_link); | TAILQ_INSERT_TAIL(&ndp->ni_cap_tracker, nt, nm_link); | ||||
| } | } | ||||
| static void | static void | ||||
| nameicap_cleanup(struct nameidata *ndp) | nameicap_cleanup(struct nameidata *ndp) | ||||
| Show All 29 Lines | nameicap_check_dotdot(struct nameidata *ndp, struct vnode *dp) | ||||
| if (lookup_cap_dotdot_nonlocal == 0 && mp != NULL && | if (lookup_cap_dotdot_nonlocal == 0 && mp != NULL && | ||||
| (mp->mnt_flag & MNT_LOCAL) == 0) | (mp->mnt_flag & MNT_LOCAL) == 0) | ||||
| return (ENOTCAPABLE); | return (ENOTCAPABLE); | ||||
| TAILQ_FOREACH_REVERSE(nt, &ndp->ni_cap_tracker, nameicap_tracker_head, | TAILQ_FOREACH_REVERSE(nt, &ndp->ni_cap_tracker, nameicap_tracker_head, | ||||
| nm_link) { | nm_link) { | ||||
| if (dp == nt->dp) | if (dp == nt->dp) | ||||
| return (0); | return (0); | ||||
| } | } | ||||
| if ((ndp->ni_lcf & NI_LCF_BENEATH_ABS) != 0) { | |||||
| ndp->ni_lcf &= ~NI_LCF_BENEATH_LATCHED; | |||||
| nameicap_cleanup(ndp); | |||||
| } | |||||
| return (ENOTCAPABLE); | return (ENOTCAPABLE); | ||||
| } | } | ||||
| static void | static void | ||||
| namei_cleanup_cnp(struct componentname *cnp) | namei_cleanup_cnp(struct componentname *cnp) | ||||
| { | { | ||||
| uma_zfree(namei_zone, cnp->cn_pnbuf); | uma_zfree(namei_zone, cnp->cn_pnbuf); | ||||
| #ifdef DIAGNOSTIC | #ifdef DIAGNOSTIC | ||||
| cnp->cn_pnbuf = NULL; | cnp->cn_pnbuf = NULL; | ||||
| cnp->cn_nameptr = NULL; | cnp->cn_nameptr = NULL; | ||||
| #endif | #endif | ||||
| } | } | ||||
| static void | |||||
| namei_cleanup_vp(struct nameidata *ndp) | |||||
| { | |||||
| vput(ndp->ni_vp); | |||||
| ndp->ni_vp = NULL; | |||||
| vrele(ndp->ni_dvp); | |||||
| } | |||||
| static int | static int | ||||
| namei_handle_root(struct nameidata *ndp, struct vnode **dpp) | namei_handle_root(struct nameidata *ndp, struct vnode **dpp) | ||||
| { | { | ||||
| struct componentname *cnp; | struct componentname *cnp; | ||||
| cnp = &ndp->ni_cnd; | cnp = &ndp->ni_cnd; | ||||
| if ((ndp->ni_lcf & NI_LCF_STRICTRELATIVE) != 0 || | if ((ndp->ni_lcf & NI_LCF_STRICTRELATIVE) != 0) { | ||||
| (cnp->cn_flags & BENEATH) != 0) { | |||||
| #ifdef KTRACE | #ifdef KTRACE | ||||
| if (KTRPOINT(curthread, KTR_CAPFAIL)) | if (KTRPOINT(curthread, KTR_CAPFAIL)) | ||||
| ktrcapfail(CAPFAIL_LOOKUP, NULL, NULL); | ktrcapfail(CAPFAIL_LOOKUP, NULL, NULL); | ||||
| #endif | #endif | ||||
| return (ENOTCAPABLE); | 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); | |||||
| } | |||||
| while (*(cnp->cn_nameptr) == '/') { | while (*(cnp->cn_nameptr) == '/') { | ||||
| cnp->cn_nameptr++; | cnp->cn_nameptr++; | ||||
| ndp->ni_pathlen--; | ndp->ni_pathlen--; | ||||
| } | } | ||||
| *dpp = ndp->ni_rootdir; | *dpp = ndp->ni_rootdir; | ||||
| vrefact(*dpp); | vrefact(*dpp); | ||||
| return (0); | return (0); | ||||
| } | } | ||||
| Show All 24 Lines | namei(struct nameidata *ndp) | ||||
| struct filedesc *fdp; /* pointer to file descriptor state */ | struct filedesc *fdp; /* pointer to file descriptor state */ | ||||
| char *cp; /* pointer into pathname argument */ | char *cp; /* pointer into pathname argument */ | ||||
| struct vnode *dp; /* the directory we are searching */ | struct vnode *dp; /* the directory we are searching */ | ||||
| struct iovec aiov; /* uio for reading symbolic links */ | struct iovec aiov; /* uio for reading symbolic links */ | ||||
| struct componentname *cnp; | struct componentname *cnp; | ||||
| struct thread *td; | struct thread *td; | ||||
| struct proc *p; | struct proc *p; | ||||
| cap_rights_t rights; | cap_rights_t rights; | ||||
| struct filecaps dirfd_caps; | |||||
| struct uio auio; | struct uio auio; | ||||
| int error, linklen, startdir_used; | int error, linklen, startdir_used; | ||||
| cnp = &ndp->ni_cnd; | cnp = &ndp->ni_cnd; | ||||
| td = cnp->cn_thread; | td = cnp->cn_thread; | ||||
| p = td->td_proc; | p = td->td_proc; | ||||
| ndp->ni_cnd.cn_cred = ndp->ni_cnd.cn_thread->td_ucred; | ndp->ni_cnd.cn_cred = ndp->ni_cnd.cn_thread->td_ucred; | ||||
| KASSERT(cnp->cn_cred && p, ("namei: bad cred/proc")); | KASSERT(cnp->cn_cred && p, ("namei: bad cred/proc")); | ||||
| ▲ Show 20 Lines • Show All 121 Lines • ▼ Show 20 Lines | #ifdef CAPABILITIES | ||||
| ndp->ni_filecaps.fc_nioctls != -1) { | ndp->ni_filecaps.fc_nioctls != -1) { | ||||
| ndp->ni_lcf |= NI_LCF_STRICTRELATIVE; | ndp->ni_lcf |= NI_LCF_STRICTRELATIVE; | ||||
| } | } | ||||
| #endif | #endif | ||||
| } | } | ||||
| if (error == 0 && dp->v_type != VDIR) | if (error == 0 && dp->v_type != VDIR) | ||||
| error = ENOTDIR; | 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); | FILEDESC_SUNLOCK(fdp); | ||||
| if (ndp->ni_startdir != NULL && !startdir_used) | if (ndp->ni_startdir != NULL && !startdir_used) | ||||
| vrele(ndp->ni_startdir); | vrele(ndp->ni_startdir); | ||||
| if (error != 0) { | if (error != 0) { | ||||
| if (dp != NULL) | if (dp != NULL) | ||||
| vrele(dp); | vrele(dp); | ||||
| goto out; | goto out; | ||||
| } | } | ||||
| Show All 13 Lines | for (;;) { | ||||
| * If not a symbolic link, we're done. | * If not a symbolic link, we're done. | ||||
| */ | */ | ||||
| if ((cnp->cn_flags & ISSYMLINK) == 0) { | if ((cnp->cn_flags & ISSYMLINK) == 0) { | ||||
| vrele(ndp->ni_rootdir); | vrele(ndp->ni_rootdir); | ||||
| if ((cnp->cn_flags & (SAVENAME | SAVESTART)) == 0) { | if ((cnp->cn_flags & (SAVENAME | SAVESTART)) == 0) { | ||||
| namei_cleanup_cnp(cnp); | namei_cleanup_cnp(cnp); | ||||
| } else | } else | ||||
| cnp->cn_flags |= HASBUF; | cnp->cn_flags |= HASBUF; | ||||
| if ((ndp->ni_lcf & (NI_LCF_BENEATH_ABS | | |||||
| NI_LCF_BENEATH_LATCHED)) == NI_LCF_BENEATH_ABS) | |||||
| error = ENOTCAPABLE; | |||||
| nameicap_cleanup(ndp); | nameicap_cleanup(ndp); | ||||
| if ((ndp->ni_lcf & NI_LCF_LATCH) != 0) | |||||
| vrele(ndp->ni_beneath_latch); | |||||
| SDT_PROBE2(vfs, namei, lookup, return, 0, ndp->ni_vp); | SDT_PROBE2(vfs, namei, lookup, return, 0, ndp->ni_vp); | ||||
| return (0); | return (error); | ||||
| } | } | ||||
| if (ndp->ni_loopcnt++ >= MAXSYMLINKS) { | if (ndp->ni_loopcnt++ >= MAXSYMLINKS) { | ||||
| error = ELOOP; | error = ELOOP; | ||||
| break; | break; | ||||
| } | } | ||||
| #ifdef MAC | #ifdef MAC | ||||
| if ((cnp->cn_flags & NOMACCHECK) == 0) { | if ((cnp->cn_flags & NOMACCHECK) == 0) { | ||||
| error = mac_vnode_check_readlink(td->td_ucred, | error = mac_vnode_check_readlink(td->td_ucred, | ||||
| ▲ Show 20 Lines • Show All 49 Lines • ▼ Show 20 Lines | #endif | ||||
| cnp->cn_nameptr = cnp->cn_pnbuf; | cnp->cn_nameptr = cnp->cn_pnbuf; | ||||
| if (*(cnp->cn_nameptr) == '/') { | if (*(cnp->cn_nameptr) == '/') { | ||||
| vrele(dp); | vrele(dp); | ||||
| error = namei_handle_root(ndp, &dp); | error = namei_handle_root(ndp, &dp); | ||||
| if (error != 0) | if (error != 0) | ||||
| goto out; | goto out; | ||||
| } | } | ||||
| } | } | ||||
| vput(ndp->ni_vp); | namei_cleanup_vp(ndp); | ||||
| ndp->ni_vp = NULL; | |||||
| vrele(ndp->ni_dvp); | |||||
| out: | out: | ||||
| vrele(ndp->ni_rootdir); | vrele(ndp->ni_rootdir); | ||||
| if (error == 0 && (ndp->ni_lcf & (NI_LCF_BENEATH_ABS | | |||||
| NI_LCF_BENEATH_LATCHED)) == NI_LCF_BENEATH_ABS) { | |||||
| namei_cleanup_vp(ndp); | |||||
| error = ENOTCAPABLE; | |||||
| } | |||||
| namei_cleanup_cnp(cnp); | namei_cleanup_cnp(cnp); | ||||
| nameicap_cleanup(ndp); | nameicap_cleanup(ndp); | ||||
| if ((ndp->ni_lcf & NI_LCF_LATCH) != 0) | |||||
| vrele(ndp->ni_beneath_latch); | |||||
| SDT_PROBE2(vfs, namei, lookup, return, error, NULL); | SDT_PROBE2(vfs, namei, lookup, return, error, NULL); | ||||
| return (error); | return (error); | ||||
| } | } | ||||
| static int | static int | ||||
| compute_cn_lkflags(struct mount *mp, int lkflags, int cnflags) | compute_cn_lkflags(struct mount *mp, int lkflags, int cnflags) | ||||
| { | { | ||||
| ▲ Show 20 Lines • Show All 890 Lines • Show Last 20 Lines | |||||