42#include "opt_capsicum.h"
43#include "opt_ktrace.h"
47#include <sys/dirent.h>
48#include <sys/kernel.h>
49#include <sys/capsicum.h>
57#include <sys/filedesc.h>
60#include <sys/syscallsubr.h>
61#include <sys/sysctl.h>
63#include <sys/ktrace.h>
66#include <machine/_inttypes.h>
69#include <security/audit/audit.h>
70#include <security/mac/mac_framework.h>
74#define NAMEI_DIAGNOSTIC 1
75#undef NAMEI_DIAGNOSTIC
79 "unsigned long",
"bool");
100 struct lock *lk __diagused;
101 const char *file __diagused;
102 int flags, line __diagused;
110 if ((
flags & LK_SHARED) == 0)
111 panic(
"invalid lock request for crossmp");
113 WITNESS_CHECKORDER(&lk->lock_object, LOP_NEWORDER, file, line,
114 flags & LK_INTERLOCK ? &VI_MTX(vp)->lock_object : NULL);
115 WITNESS_LOCK(&lk->lock_object, 0, file, line);
116 if ((
flags & LK_INTERLOCK) != 0)
118 LOCK_LOG_LOCK(
"SLOCK", &lk->lock_object, 0, 0, ap->a_file, line);
126 struct lock *lk __diagused;
131 WITNESS_UNLOCK(&lk->lock_object, 0, LOCK_FILE, LOCK_LINE);
132 LOCK_LOG_LOCK(
"SUNLOCK", &lk->lock_object, 0, 0, LOCK_FILE,
160 namei_zone = uma_zcreate(
"NAMEI", MAXPATHLEN, NULL, NULL, NULL, NULL,
170 "enables \"..\" components in path lookup in capability mode");
174 "enables \"..\" components in path lookup in capability mode "
175 "on non-local mount");
182 if ((ndp->ni_lcf & NI_LCF_CAP_DOTDOT) == 0 ||
dp->v_type != VDIR)
184 nt = TAILQ_LAST(&ndp->ni_cap_tracker, nameicap_tracker_head);
185 if (nt != NULL && nt->
dp ==
dp)
187 nt =
malloc(
sizeof(*nt), M_NAMEITRACKER, M_WAITOK);
190 TAILQ_INSERT_TAIL(&ndp->ni_cap_tracker, nt, nm_link);
199 TAILQ_FOREACH_FROM_SAFE(nt, &ndp->ni_cap_tracker, nm_link, nt1) {
200 TAILQ_REMOVE(&ndp->ni_cap_tracker, nt, nm_link);
202 free(nt, M_NAMEITRACKER);
209 KASSERT(TAILQ_EMPTY(&ndp->ni_cap_tracker) ||
210 (ndp->ni_lcf & NI_LCF_CAP_DOTDOT) != 0, (
"not strictrelative"));
231 if (dp == NULL || dp->v_type != VDIR || (ndp->ni_lcf &
232 NI_LCF_STRICTRELATIVE) == 0)
234 if ((ndp->ni_lcf & NI_LCF_CAP_DOTDOT) == 0)
235 return (ENOTCAPABLE);
238 (mp->mnt_flag & MNT_LOCAL) == 0)
239 return (ENOTCAPABLE);
240 TAILQ_FOREACH_REVERSE(nt, &ndp->ni_cap_tracker, nameicap_tracker_head,
243 nt = TAILQ_NEXT(nt, nm_link);
249 return (ENOTCAPABLE);
258 cnp->cn_pnbuf = NULL;
259 cnp->cn_nameptr = NULL;
266 struct componentname *cnp;
269 if ((ndp->ni_lcf & NI_LCF_STRICTRELATIVE) != 0) {
271 if (KTRPOINT(curthread, KTR_CAPFAIL))
272 ktrcapfail(CAPFAIL_LOOKUP, NULL, NULL);
274 return (ENOTCAPABLE);
276 while (*(cnp->cn_nameptr) ==
'/') {
280 *dpp = ndp->ni_rootdir;
286namei_setup(
struct nameidata *ndp,
struct vnode **dpp,
struct pwd **pwdp)
288 struct componentname *cnp;
299 startdir_used =
false;
303#ifdef CAPABILITY_MODE
317 if (IN_CAPABILITY_MODE(td) && (cnp->cn_flags & NOCAPCHECK) == 0) {
318 ndp->ni_lcf |= NI_LCF_STRICTRELATIVE;
319 ndp->ni_resflags |= NIRES_STRICTREL;
320 if (ndp->ni_dirfd == AT_FDCWD) {
322 if (KTRPOINT(td, KTR_CAPFAIL))
323 ktrcapfail(CAPFAIL_LOOKUP, NULL, NULL);
339 ndp->ni_rootdir = pwd->pwd_rdir;
340 ndp->ni_topdir = pwd->pwd_jdir;
342 if (cnp->cn_pnbuf[0] ==
'/') {
343 ndp->ni_resflags |= NIRES_ABS;
346 if (ndp->ni_startdir != NULL) {
347 *dpp = ndp->ni_startdir;
348 startdir_used =
true;
349 }
else if (ndp->ni_dirfd == AT_FDCWD) {
350 *dpp = pwd->pwd_cdir;
353 rights = *ndp->ni_rightsneeded;
354 cap_rights_set_one(&rights, CAP_LOOKUP);
356 if (cnp->cn_flags & AUDITVNODE1)
357 AUDIT_ARG_ATFD1(ndp->ni_dirfd);
358 if (cnp->cn_flags & AUDITVNODE2)
359 AUDIT_ARG_ATFD2(ndp->ni_dirfd);
366 error =
fget_cap(td, ndp->ni_dirfd, &rights,
367 &dfp, &ndp->ni_filecaps);
377 }
else if (dfp->f_vnode == NULL) {
383 if ((dfp->f_flag & FSEARCH) != 0)
384 cnp->cn_flags |= NOEXECCHECK;
395 if (!cap_rights_contains(&ndp->ni_filecaps.fc_rights,
397 ndp->ni_filecaps.fc_fcntls != CAP_FCNTL_ALL ||
398 ndp->ni_filecaps.fc_nioctls != -1) {
399 ndp->ni_lcf |= NI_LCF_STRICTRELATIVE;
400 ndp->ni_resflags |= NIRES_STRICTREL;
404 if (error == 0 && (*dpp)->v_type != VDIR &&
405 (cnp->cn_pnbuf[0] !=
'\0' ||
406 (cnp->cn_flags & EMPTYPATH) == 0))
409 if (error == 0 && (cnp->cn_flags & RBENEATH) != 0) {
410 if (cnp->cn_pnbuf[0] ==
'/') {
412 }
else if ((ndp->ni_lcf & NI_LCF_STRICTRELATIVE) == 0) {
413 ndp->ni_lcf |= NI_LCF_STRICTRELATIVE |
421 if (cnp->cn_flags & AUDITVNODE1)
422 AUDIT_ARG_UPATH1_VP(td, ndp->ni_rootdir, *dpp, cnp->cn_pnbuf);
423 if (cnp->cn_flags & AUDITVNODE2)
424 AUDIT_ARG_UPATH2_VP(td, ndp->ni_rootdir, *dpp, cnp->cn_pnbuf);
425 if (ndp->ni_startdir != NULL && !startdir_used)
426 vrele(ndp->ni_startdir);
433 if ((ndp->ni_lcf & NI_LCF_STRICTRELATIVE) != 0 &&
435 ndp->ni_lcf |= NI_LCF_CAP_DOTDOT;
436 SDT_PROBE4(vfs,
namei, lookup, entry, *dpp, cnp->cn_pnbuf,
437 cnp->cn_flags,
false);
445 struct componentname *cnp;
454 cnp->cn_pnbuf = uma_zalloc(
namei_zone, M_WAITOK);
455 if (ndp->ni_segflg == UIO_SYSSPACE) {
456 error = copystr(ndp->ni_dirp, cnp->cn_pnbuf, MAXPATHLEN,
459 error = copyinstr(ndp->ni_dirp, cnp->cn_pnbuf, MAXPATHLEN,
463 if (__predict_false(error != 0))
466 cnp->cn_nameptr = cnp->cn_pnbuf;
473 struct componentname *cnp;
479 MPASS(*cnp->cn_pnbuf ==
'\0');
480 MPASS((cnp->cn_flags & EMPTYPATH) != 0);
481 MPASS((cnp->cn_flags & (LOCKPARENT | WANTPARENT)) == 0);
483 ndp->ni_resflags |= NIRES_EMPTYPATH;
497 if ((cnp->cn_flags & LOCKLEAF) != 0) {
498 VOP_LOCK(dp, (cnp->cn_flags & LOCKSHARED) != 0 ?
499 LK_SHARED : LK_EXCLUSIVE);
500 if (VN_IS_DOOMED(dp)) {
506 SDT_PROBE4(vfs,
namei, lookup,
return, 0, ndp->ni_vp,
false, ndp);
510 SDT_PROBE4(vfs,
namei, lookup,
return, error, NULL,
false, ndp);
540 struct componentname *cnp;
545 enum cache_fpl_status status;
550 KASSERT((ndp->ni_debugflags & NAMEI_DBG_CALLED) == 0,
551 (
"%s: repeated call to namei without NDREINIT", __func__));
552 KASSERT(ndp->ni_debugflags == NAMEI_DBG_INITED,
553 (
"%s: bad debugflags %d", __func__, ndp->ni_debugflags));
554 ndp->ni_debugflags |= NAMEI_DBG_CALLED;
555 if (ndp->ni_startdir != NULL)
556 ndp->ni_debugflags |= NAMEI_DBG_HADSTARTDIR;
557 if (cnp->cn_flags & FAILIFEXISTS) {
558 KASSERT(cnp->cn_nameiop == CREATE,
559 (
"%s: FAILIFEXISTS passed for op %d", __func__, cnp->cn_nameiop));
563 KASSERT((cnp->cn_flags & (LOCKPARENT | LOCKLEAF)) == LOCKPARENT,
564 (
"%s: FAILIFEXISTS must be passed with LOCKPARENT and without LOCKLEAF",
573 cnp->cn_origflags = cnp->cn_flags;
575 ndp->ni_cnd.cn_cred = td->td_ucred;
576 KASSERT(ndp->ni_resflags == 0, (
"%s: garbage in ni_resflags: %x\n",
577 __func__, ndp->ni_resflags));
578 KASSERT(cnp->cn_cred && td->td_proc, (
"namei: bad cred/proc"));
579 KASSERT((cnp->cn_flags & NAMEI_INTERNAL_FLAGS) == 0,
580 (
"namei: unexpected flags: %" PRIx64
"\n",
581 cnp->cn_flags & NAMEI_INTERNAL_FLAGS));
582 if (cnp->cn_flags & NOCACHE)
583 KASSERT(cnp->cn_nameiop != LOOKUP,
584 (
"%s: NOCACHE passed with LOOKUP", __func__));
585 MPASS(ndp->ni_startdir == NULL || ndp->ni_startdir->v_type == VDIR ||
586 ndp->ni_startdir->v_type == VBAD);
593 if (__predict_false(error != 0)) {
595 SDT_PROBE4(vfs,
namei, lookup,
return, error, NULL,
601 if (KTRPOINT(td, KTR_NAMEI)) {
602 ktrnamei(cnp->cn_pnbuf);
605 TSNAMEI(curthread->td_proc->p_pid, cnp->cn_pnbuf);
614 case CACHE_FPL_STATUS_UNSET:
615 __assert_unreachable();
617 case CACHE_FPL_STATUS_HANDLED:
621 case CACHE_FPL_STATUS_PARTIAL:
622 TAILQ_INIT(&ndp->ni_cap_tracker);
623 dp = ndp->ni_startdir;
625 case CACHE_FPL_STATUS_DESTROYED:
628 if (__predict_false(error != 0)) {
633 case CACHE_FPL_STATUS_ABORTED:
634 TAILQ_INIT(&ndp->ni_cap_tracker);
635 MPASS(ndp->ni_lcf == 0);
636 if (*cnp->cn_pnbuf ==
'\0') {
637 if ((cnp->cn_flags & EMPTYPATH) != 0) {
641 SDT_PROBE4(vfs,
namei, lookup,
return, ENOENT, NULL,
657 ndp->ni_startdir = dp;
665 if ((cnp->cn_flags & ISSYMLINK) == 0) {
666 SDT_PROBE4(vfs,
namei, lookup,
return, error,
667 (error == 0 ? ndp->ni_vp : NULL),
false, ndp);
668 if ((cnp->cn_flags & (SAVENAME | SAVESTART)) == 0) {
671 cnp->cn_flags |= HASBUF;
678 if (ndp->ni_loopcnt++ >= MAXSYMLINKS) {
683 if ((cnp->cn_flags & NOMACCHECK) == 0) {
684 error = mac_vnode_check_readlink(td->td_ucred,
690 if (ndp->ni_pathlen > 1)
695 aiov.iov_len = MAXPATHLEN;
696 auio.uio_iov = &aiov;
699 auio.uio_rw = UIO_READ;
700 auio.uio_segflg = UIO_SYSSPACE;
702 auio.uio_resid = MAXPATHLEN;
703 error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred);
705 if (ndp->ni_pathlen > 1)
709 linklen = MAXPATHLEN - auio.uio_resid;
711 if (ndp->ni_pathlen > 1)
716 if (linklen + ndp->ni_pathlen > MAXPATHLEN) {
717 if (ndp->ni_pathlen > 1)
719 error = ENAMETOOLONG;
722 if (ndp->ni_pathlen > 1) {
723 bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen);
727 cnp->cn_pnbuf[linklen] =
'\0';
728 ndp->ni_pathlen += linklen;
734 cnp->cn_nameptr = cnp->cn_pnbuf;
735 if (*(cnp->cn_nameptr) ==
'/') {
747 SDT_PROBE4(vfs,
namei, lookup,
return, error, NULL,
false, ndp);
758 if (mp == NULL || ((lkflags & LK_SHARED) &&
759 !(mp->mnt_kern_flag & MNTK_LOOKUP_SHARED))) {
760 lkflags &= ~LK_SHARED;
761 lkflags |= LK_EXCLUSIVE;
763 lkflags |= LK_NODDLKTREAT;
775 if ((
flags & (ISLASTCN | LOCKLEAF)) != (ISLASTCN | LOCKLEAF))
779 if (!(
flags & LOCKSHARED))
787 if ((
flags & ISOPEN) != 0)
788 return (!MNT_EXTENDED_SHARED(mp));
803 "MAXNAMLEN and NAME_MAX have different values");
849 struct vnode *dp = NULL;
853 size_t prev_ni_pathlen;
860 struct componentname *cnp = &ndp->ni_cnd;
868 wantparent = cnp->cn_flags & (LOCKPARENT | WANTPARENT);
869 KASSERT(cnp->cn_nameiop == LOOKUP || wantparent,
870 (
"CREATE, DELETE, RENAME require LOCKPARENT or WANTPARENT."));
881 docache = (cnp->cn_flags & NOCACHE) ^ NOCACHE;
882 if (cnp->cn_nameiop == DELETE ||
883 (wantparent && cnp->cn_nameiop != CREATE &&
884 cnp->cn_nameiop != LOOKUP))
886 rdonly = cnp->cn_flags & RDONLY;
887 cnp->cn_flags &= ~ISSYMLINK;
893 cnp->cn_lkflags = LK_SHARED;
894 dp = ndp->ni_startdir;
895 ndp->ni_startdir = NULLVP;
913 nulchar = &cnp->cn_nameptr[ndp->ni_pathlen - 1];
914 KASSERT(*nulchar ==
'\0',
915 (
"%s: expected nul at %p; string [%s]\n", __func__, nulchar,
918 for (cp = cnp->cn_nameptr; *cp !=
'/'; cp++) {
920 (
"%s: encountered unexpected nul; string [%s]\n", __func__,
925 cnp->cn_namelen = cp - cnp->cn_nameptr;
926 if (cnp->cn_namelen > NAME_MAX) {
927 error = ENAMETOOLONG;
930#ifdef NAMEI_DIAGNOSTIC
933 printf(
"{%s}: ", cnp->cn_nameptr);
936 prev_ni_pathlen = ndp->ni_pathlen;
937 ndp->ni_pathlen -= cnp->cn_namelen;
938 KASSERT(ndp->ni_pathlen <= PATH_MAX,
939 (
"%s: ni_pathlen underflow to %zd\n", __func__, ndp->ni_pathlen));
940 prev_ni_next = ndp->ni_next;
950 while (*cp ==
'/' && (cp[1] ==
'/' || cp[1] ==
'\0')) {
954 *ndp->ni_next =
'\0';
955 cnp->cn_flags |= TRAILINGSLASH;
960 cnp->cn_flags |= MAKEENTRY;
961 if (*cp ==
'\0' && docache == 0)
962 cnp->cn_flags &= ~MAKEENTRY;
963 if (cnp->cn_namelen == 2 &&
964 cnp->cn_nameptr[1] ==
'.' && cnp->cn_nameptr[0] ==
'.')
965 cnp->cn_flags |= ISDOTDOT;
967 cnp->cn_flags &= ~ISDOTDOT;
968 if (*ndp->ni_next == 0)
969 cnp->cn_flags |= ISLASTCN;
971 cnp->cn_flags &= ~ISLASTCN;
973 if ((cnp->cn_flags & ISLASTCN) != 0 &&
974 cnp->cn_namelen == 1 && cnp->cn_nameptr[0] ==
'.' &&
975 (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) {
987 if (cnp->cn_nameptr[0] ==
'\0') {
988 if (dp->v_type != VDIR) {
992 if (cnp->cn_nameiop != LOOKUP) {
1002 if (cnp->cn_flags & AUDITVNODE1)
1003 AUDIT_ARG_VNODE1(dp);
1004 else if (cnp->cn_flags & AUDITVNODE2)
1005 AUDIT_ARG_VNODE2(dp);
1007 if (!(cnp->cn_flags & (LOCKPARENT | LOCKLEAF)))
1010 if (cnp->cn_flags & SAVESTART)
1011 panic(
"lookup: SAVESTART");
1036 if (cnp->cn_flags & ISDOTDOT) {
1037 if ((ndp->ni_lcf & (NI_LCF_STRICTRELATIVE | NI_LCF_CAP_DOTDOT))
1038 == NI_LCF_STRICTRELATIVE) {
1040 if (KTRPOINT(curthread, KTR_CAPFAIL))
1041 ktrcapfail(CAPFAIL_LOOKUP, NULL, NULL);
1043 error = ENOTCAPABLE;
1046 if ((cnp->cn_flags & ISLASTCN) != 0 &&
1047 (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) {
1052 for (
pr = cnp->cn_cred->cr_prison;
pr != NULL;
1054 if (dp ==
pr->pr_root)
1056 if (dp == ndp->ni_rootdir ||
1057 dp == ndp->ni_topdir ||
1060 ((dp->v_vflag & VV_ROOT) != 0 &&
1061 (cnp->cn_flags & NOCROSSMOUNT) != 0)) {
1067 if ((dp->v_vflag & VV_ROOT) == 0)
1069 if (VN_IS_DOOMED(dp)) {
1074 dp = dp->v_mount->mnt_vnodecovered;
1079 LK_RETRY, ISDOTDOT));
1083 if (KTRPOINT(curthread, KTR_CAPFAIL))
1084 ktrcapfail(CAPFAIL_LOOKUP, NULL, NULL);
1096 error = mac_vnode_check_lookup(cnp->cn_cred, dp, cnp);
1102 ASSERT_VOP_LOCKED(dp,
"lookup");
1107 if ((cnp->cn_flags & LOCKPARENT) && (cnp->cn_flags & ISLASTCN) &&
1108 dp !=
vp_crossmp && VOP_ISLOCKED(dp) == LK_SHARED)
1109 vn_lock(dp, LK_UPGRADE|LK_RETRY);
1110 if (VN_IS_DOOMED(dp)) {
1119 cnp->cn_lkflags = LK_EXCLUSIVE;
1120#ifdef NAMEI_DIAGNOSTIC
1123 lkflags_save = cnp->cn_lkflags;
1126 error = VOP_LOOKUP(dp, &ndp->ni_vp, cnp);
1127 cnp->cn_lkflags = lkflags_save;
1129 KASSERT(ndp->ni_vp == NULL, (
"leaf should be empty"));
1130#ifdef NAMEI_DIAGNOSTIC
1133 if ((error == ENOENT) &&
1134 (dp->v_vflag & VV_ROOT) && (dp->v_mount != NULL) &&
1135 (dp->v_mount->mnt_flag & MNT_UNION)) {
1137 dp = dp->v_mount->mnt_vnodecovered;
1142 LK_RETRY, cnp->cn_flags));
1147 if (error == ERELOOKUP) {
1155 if (error != EJUSTRETURN)
1168 if ((cnp->cn_flags & TRAILINGSLASH) &&
1169 !(cnp->cn_flags & WILLBEDIR)) {
1173 if ((cnp->cn_flags & LOCKPARENT) == 0)
1180 if (cnp->cn_flags & SAVESTART) {
1181 ndp->ni_startdir = ndp->ni_dvp;
1182 VREF(ndp->ni_startdir);
1188#ifdef NAMEI_DIAGNOSTIC
1197 while (dp->v_type == VDIR && (mp = dp->v_mountedhere) &&
1198 (cnp->cn_flags & NOCROSSMOUNT) == 0) {
1202 if (dp != ndp->ni_dvp)
1209 cnp->cn_flags), &tdp);
1211 if (vn_lock(
vp_crossmp, LK_SHARED | LK_NOWAIT))
1212 panic(
"vp_crossmp exclusively locked or reclaimed");
1217 ndp->ni_vp = dp = tdp;
1223 if ((dp->v_type == VLNK) &&
1224 ((cnp->cn_flags & FOLLOW) || (cnp->cn_flags & TRAILINGSLASH) ||
1225 *ndp->ni_next ==
'/')) {
1226 cnp->cn_flags |= ISSYMLINK;
1227 if (VN_IS_DOOMED(dp)) {
1235 if (dp->v_mount->mnt_flag & MNT_NOSYMFOLLOW) {
1242 if (ndp->ni_dvp != ndp->ni_vp) {
1243 VOP_UNLOCK(ndp->ni_dvp);
1244 ni_dvp_unlocked = 1;
1254 KASSERT((cnp->cn_flags & ISLASTCN) || *ndp->ni_next ==
'/',
1255 (
"lookup: invalid path state."));
1258 ndp->ni_pathlen = prev_ni_pathlen;
1259 ndp->ni_next = prev_ni_next;
1260 if (ndp->ni_dvp != dp)
1266 if (cnp->cn_flags & ISDOTDOT) {
1270 if (KTRPOINT(curthread, KTR_CAPFAIL))
1271 ktrcapfail(CAPFAIL_LOOKUP, NULL, NULL);
1276 if (*ndp->ni_next ==
'/') {
1277 cnp->cn_nameptr = ndp->ni_next;
1278 while (*cnp->cn_nameptr ==
'/') {
1282 if (ndp->ni_dvp != dp)
1292 if ((cnp->cn_flags & TRAILINGSLASH) && dp->v_type != VDIR) {
1300 (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) {
1304 if (cnp->cn_flags & SAVESTART) {
1305 ndp->ni_startdir = ndp->ni_dvp;
1306 VREF(ndp->ni_startdir);
1309 ni_dvp_unlocked = 2;
1310 if (ndp->ni_dvp != dp)
1314 }
else if ((cnp->cn_flags & LOCKPARENT) == 0 && ndp->ni_dvp != dp) {
1315 VOP_UNLOCK(ndp->ni_dvp);
1316 ni_dvp_unlocked = 1;
1319 if (cnp->cn_flags & AUDITVNODE1)
1320 AUDIT_ARG_VNODE1(dp);
1321 else if (cnp->cn_flags & AUDITVNODE2)
1322 AUDIT_ARG_VNODE2(dp);
1324 if ((cnp->cn_flags & LOCKLEAF) == 0)
1337 VOP_ISLOCKED(dp) != LK_EXCLUSIVE) {
1338 vn_lock(dp, LK_UPGRADE | LK_RETRY);
1339 if (VN_IS_DOOMED(dp)) {
1344 if (ndp->ni_vp != NULL) {
1345 if ((cnp->cn_flags & ISDOTDOT) == 0)
1347 if ((cnp->cn_flags & (FAILIFEXISTS | ISSYMLINK)) == FAILIFEXISTS)
1353 if (ni_dvp_unlocked != 2) {
1354 if (dp != ndp->ni_dvp && !ni_dvp_unlocked)
1372 MPASS((cnp->cn_flags & ISSYMLINK) == 0);
1373 if (ndp->ni_vp == ndp->ni_dvp)
1380 NDFREE(ndp, NDF_ONLY_PNBUF);
1389vfs_relookup(
struct vnode *dvp,
struct vnode **vpp,
struct componentname *cnp)
1391 struct vnode *dp = NULL;
1395 KASSERT(cnp->cn_flags & ISLASTCN,
1396 (
"relookup: Not given last component."));
1400 KASSERT((cnp->cn_flags & (LOCKPARENT | WANTPARENT)) != 0,
1401 (
"relookup: parent not wanted"));
1402 rdonly = cnp->cn_flags & RDONLY;
1403 cnp->cn_flags &= ~ISSYMLINK;
1405 cnp->cn_lkflags = LK_EXCLUSIVE;
1406 vn_lock(dp, LK_EXCLUSIVE | LK_RETRY);
1416#ifdef NAMEI_DIAGNOSTIC
1417 printf(
"{%s}: ", cnp->cn_nameptr);
1424 if (cnp->cn_nameptr[0] ==
'\0') {
1429 KASSERT(cnp->cn_nameiop == LOOKUP, (
"nameiop must be LOOKUP"));
1430 KASSERT(dp->v_type == VDIR, (
"dp is not a directory"));
1432 if (!(cnp->cn_flags & LOCKLEAF))
1436 if (cnp->cn_flags & SAVESTART)
1437 panic(
"lookup: SAVESTART");
1441 if (cnp->cn_flags & ISDOTDOT)
1442 panic (
"relookup: lookup on dot-dot");
1447#ifdef NAMEI_DIAGNOSTIC
1450 if ((error = VOP_LOOKUP(dp, vpp, cnp)) != 0) {
1451 KASSERT(*vpp == NULL, (
"leaf should be empty"));
1452 if (error != EJUSTRETURN)
1463 if (cnp->cn_flags & SAVESTART)
1465 if ((cnp->cn_flags & LOCKPARENT) == 0)
1481 (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) {
1492 if ((cnp->cn_flags & LOCKPARENT) == 0 && dvp != dp)
1497 KASSERT(dp->v_type != VLNK || !(cnp->cn_flags & FOLLOW),
1498 (
"relookup: symlink found.\n"));
1501 if (cnp->cn_flags & SAVESTART)
1504 if ((cnp->cn_flags & LOCKLEAF) == 0)
1520 if ((ndp->ni_cnd.cn_flags & HASBUF) != 0) {
1521 MPASS((ndp->ni_cnd.cn_flags & (SAVENAME | SAVESTART)) != 0);
1523 ndp->ni_cnd.cn_flags &= ~HASBUF;
1542NDFREE_NOTHING(
struct nameidata *ndp)
1544 struct componentname *cnp;
1547 KASSERT(cnp->cn_nameiop == LOOKUP, (
"%s: got non-LOOKUP op %d\n",
1548 __func__, cnp->cn_nameiop));
1549 KASSERT((cnp->cn_flags & (SAVENAME | HASBUF)) == 0,
1550 (
"%s: bad flags \%" PRIx64
"\n", __func__, cnp->cn_flags));
1563 if (!(
flags & NDF_NO_FREE_PNBUF)) {
1566 if (!(
flags & NDF_NO_VP_UNLOCK) &&
1567 (ndp->ni_cnd.cn_flags & LOCKLEAF) && ndp->ni_vp)
1569 if (!(
flags & NDF_NO_DVP_UNLOCK) &&
1570 (ndp->ni_cnd.cn_flags & LOCKPARENT) &&
1571 ndp->ni_dvp != ndp->ni_vp)
1573 if (!(
flags & NDF_NO_VP_RELE) && ndp->ni_vp) {
1582 VOP_UNLOCK(ndp->ni_vp);
1583 if (!(
flags & NDF_NO_DVP_RELE) &&
1584 (ndp->ni_cnd.cn_flags & (LOCKPARENT|WANTPARENT))) {
1593 VOP_UNLOCK(ndp->ni_dvp);
1594 if (!(
flags & NDF_NO_STARTDIR_RELE) &&
1595 (ndp->ni_cnd.cn_flags & SAVESTART)) {
1596 vrele(ndp->ni_startdir);
1597 ndp->ni_startdir = NULL;
1614#define NDMODIFYINGFLAGS (LOCKLEAF | LOCKPARENT | WANTPARENT | SAVENAME | SAVESTART | HASBUF)
1616NDVALIDATE(
struct nameidata *ndp)
1618 struct componentname *cnp;
1619 uint64_t used, orig;
1622 orig = cnp->cn_origflags;
1623 used = cnp->cn_flags;
1624 switch (cnp->cn_nameiop) {
1630 orig &= NDMODIFYINGFLAGS;
1631 used &= NDMODIFYINGFLAGS;
1632 if ((orig & (SAVENAME | SAVESTART)) != 0)
1645 orig &= NDMODIFYINGFLAGS;
1646 orig |= (SAVENAME | HASBUF);
1647 used &= NDMODIFYINGFLAGS;
1648 used |= (SAVENAME | HASBUF);
1656 panic(
"%s: mismatched flags for op %d: added %" PRIx64
", "
1657 "removed %" PRIx64
" (%" PRIx64
" != %" PRIx64
"; stored %" PRIx64
" != %" PRIx64
")",
1658 __func__, cnp->cn_nameiop, used & ~orig, orig &~ used,
1659 orig, used, cnp->cn_origflags, cnp->cn_flags);
1675 char **pathbuf,
int create,
int dirfd)
1677 struct nameidata nd, ndroot;
1678 char *ptr, *
buf, *cp;
1682 buf = (
char *)
malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
1686 len = strlcpy(
buf, prefix, MAXPATHLEN);
1687 if (len >= MAXPATHLEN) {
1692 sz = MAXPATHLEN - len;
1696 if (pathseg == UIO_SYSSPACE)
1697 error = copystr(
path, ptr, sz, &len);
1699 error = copyinstr(
path, ptr, sz, &len);
1713 if (
dirfd != AT_FDCWD) {
1718 bcopy(ptr,
buf, len);
1731 for (cp = &ptr[len] - 1; *cp !=
'/'; cp--);
1734 NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_SYSSPACE,
buf);
1740 NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_SYSSPACE,
buf);
1754 NDINIT(&ndroot, LOOKUP, FOLLOW, UIO_SYSSPACE, prefix);
1757 error =
namei(&ndroot);
1759 if (nd.ni_vp == ndroot.ni_vp)
1762 NDFREE(&ndroot, NDF_ONLY_PNBUF);
1763 vrele(ndroot.ni_vp);
1767 NDFREE(&nd, NDF_ONLY_PNBUF);
1773 bcopy(ptr,
buf, len);
struct pwd * pwd_hold(struct thread *td)
void pwd_drop(struct pwd *pwd)
int fget_cap(struct thread *td, int fd, cap_rights_t *needrightsp, struct file **fpp, struct filecaps *havecapsp)
struct fileops badfileops
void *() malloc(size_t size, struct malloc_type *mtp, int flags)
void free(void *addr, struct malloc_type *mtp)
static struct pollrec pr[POLL_LIST_LEN]
void panic(const char *fmt,...)
int printf(const char *fmt,...)
int cache_fplookup(struct nameidata *ndp, enum cache_fpl_status *status, struct pwd **pwdp)
struct vop_vector default_vnodeops
static void nameicap_tracker_add(struct nameidata *ndp, struct vnode *dp)
static int namei_emptypath(struct nameidata *ndp)
MALLOC_DEFINE(M_NAMEITRACKER, "namei_tracker", "namei tracking for dotdot")
int kern_alternate_path(const char *prefix, const char *path, enum uio_seg pathseg, char **pathbuf, int create, int dirfd)
static int namei_setup(struct nameidata *ndp, struct vnode **dpp, struct pwd **pwdp)
void NDFREE_PNBUF(struct nameidata *ndp)
static struct vop_vector crossmp_vnodeops
static void nameicap_cleanup(struct nameidata *ndp)
SDT_PROBE_DEFINE4(vfs, namei, lookup, entry, "struct vnode *", "char *", "unsigned long", "bool")
SYSINIT(vfs, SI_SUB_VFS, SI_ORDER_SECOND, nameiinit, NULL)
static int crossmp_vop_unlock(struct vop_unlock_args *ap)
int vfs_relookup(struct vnode *dvp, struct vnode **vpp, struct componentname *cnp)
static int nameicap_check_dotdot(struct nameidata *ndp, struct vnode *dp)
static void nameiinit(void *dummy __unused)
static void namei_cleanup_cnp(struct componentname *cnp)
static int namei_handle_root(struct nameidata *ndp, struct vnode **dpp)
void() NDFREE(struct nameidata *ndp, const u_int flags)
static __inline int needs_exclusive_leaf(struct mount *mp, int flags)
static int lookup_cap_dotdot
static int crossmp_vop_islocked(struct vop_islocked_args *ap)
static int lookup_cap_dotdot_nonlocal
int vfs_lookup(struct nameidata *ndp)
_Static_assert(MAXNAMLEN==NAME_MAX, "MAXNAMLEN and NAME_MAX have different values")
static int crossmp_vop_lock1(struct vop_lock1_args *ap)
static void nameicap_cleanup_from(struct nameidata *ndp, struct nameicap_tracker *first)
static int namei_getpath(struct nameidata *ndp)
static int compute_cn_lkflags(struct mount *mp, int lkflags, int cnflags)
static struct vnode * vp_crossmp
SYSCTL_INT(_vfs, OID_AUTO, lookup_cap_dotdot, CTLFLAG_RWTUN, &lookup_cap_dotdot, 0, "enables \"..\" components in path lookup in capability mode")
int namei(struct nameidata *ndp)
void vhold(struct vnode *vp)
int getnewvnode(const char *tag, struct mount *mp, struct vop_vector *vops, struct vnode **vpp)
void vref(struct vnode *vp)
void vn_printf(struct vnode *vp, const char *fmt,...)
void vfs_unbusy(struct mount *mp)
void vrefact(struct vnode *vp)
void vrele(struct vnode *vp)
void vput(struct vnode *vp)
int vfs_busy(struct mount *mp, int flags)
void vdrop(struct vnode *vp)