Changeset View
Changeset View
Standalone View
Standalone View
sys/kern/vfs_lookup.c
| Show First 20 Lines • Show All 176 Lines • ▼ Show 20 Lines | |||||
| #ifdef CAPABILITY_MODE | #ifdef CAPABILITY_MODE | ||||
| /* | /* | ||||
| * In capability mode, lookups must be "strictly relative" (i.e. | * In capability mode, lookups must be "strictly relative" (i.e. | ||||
| * not an absolute path, and not containing '..' components) to | * not an absolute path, and not containing '..' components) to | ||||
| * a real file descriptor, not the pseudo-descriptor AT_FDCWD. | * a real file descriptor, not the pseudo-descriptor AT_FDCWD. | ||||
| */ | */ | ||||
| if (error == 0 && IN_CAPABILITY_MODE(td) && | if (error == 0 && IN_CAPABILITY_MODE(td) && | ||||
| (cnp->cn_flags & NOCAPCHECK) == 0) { | (cnp->cn_flags & NOCAPCHECK) == 0) { | ||||
| ndp->ni_strictrelative = 1; | ndrequire_strict_relative_lookups(ndp, ENOTCAPABLE); | ||||
| if (ndp->ni_dirfd == AT_FDCWD) { | if (ndp->ni_dirfd == AT_FDCWD) { | ||||
| #ifdef KTRACE | #ifdef KTRACE | ||||
| if (KTRPOINT(td, KTR_CAPFAIL)) | if (KTRPOINT(td, KTR_CAPFAIL)) | ||||
| ktrcapfail(CAPFAIL_LOOKUP, NULL, NULL); | ktrcapfail(CAPFAIL_LOOKUP, NULL, NULL); | ||||
| #endif | #endif | ||||
| error = ECAPMODE; | error = ECAPMODE; | ||||
| } | } | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 49 Lines • ▼ Show 20 Lines | #ifdef CAPABILITIES | ||||
| * all lookups relative to it must also be | * all lookups relative to it must also be | ||||
| * strictly relative. | * strictly relative. | ||||
| */ | */ | ||||
| CAP_ALL(&rights); | CAP_ALL(&rights); | ||||
| if (!cap_rights_contains(&ndp->ni_filecaps.fc_rights, | if (!cap_rights_contains(&ndp->ni_filecaps.fc_rights, | ||||
| &rights) || | &rights) || | ||||
| ndp->ni_filecaps.fc_fcntls != CAP_FCNTL_ALL || | ndp->ni_filecaps.fc_fcntls != CAP_FCNTL_ALL || | ||||
| ndp->ni_filecaps.fc_nioctls != -1) { | ndp->ni_filecaps.fc_nioctls != -1) { | ||||
| ndp->ni_strictrelative = 1; | ndrequire_strict_relative_lookups(ndp, ENOTCAPABLE); | ||||
| } | } | ||||
| #endif | #endif | ||||
| } | } | ||||
| if (error != 0 || dp != NULL) { | if (error != 0 || dp != NULL) { | ||||
| FILEDESC_SUNLOCK(fdp); | FILEDESC_SUNLOCK(fdp); | ||||
| if (error == 0 && dp->v_type != VDIR) { | if (error == 0 && dp->v_type != VDIR) { | ||||
| vrele(dp); | vrele(dp); | ||||
| error = ENOTDIR; | error = ENOTDIR; | ||||
| Show All 16 Lines | #endif | ||||
| for (;;) { | for (;;) { | ||||
| /* | /* | ||||
| * Check if root directory should replace current directory. | * Check if root directory should replace current directory. | ||||
| * Done at start of translation and after symbolic link. | * Done at start of translation and after symbolic link. | ||||
| */ | */ | ||||
| cnp->cn_nameptr = cnp->cn_pnbuf; | cnp->cn_nameptr = cnp->cn_pnbuf; | ||||
| if (*(cnp->cn_nameptr) == '/') { | if (*(cnp->cn_nameptr) == '/') { | ||||
| vrele(dp); | vrele(dp); | ||||
| if (ndp->ni_strictrelative != 0) { | if (ndp->ni_nonrelativeerrno != 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 | ||||
| namei_cleanup_cnp(cnp); | namei_cleanup_cnp(cnp); | ||||
| return (ENOTCAPABLE); | return (ndp->ni_nonrelativeerrno); | ||||
| } | } | ||||
| while (*(cnp->cn_nameptr) == '/') { | while (*(cnp->cn_nameptr) == '/') { | ||||
| cnp->cn_nameptr++; | cnp->cn_nameptr++; | ||||
| ndp->ni_pathlen--; | ndp->ni_pathlen--; | ||||
| } | } | ||||
| dp = ndp->ni_rootdir; | dp = ndp->ni_rootdir; | ||||
| VREF(dp); | VREF(dp); | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 318 Lines • ▼ Show 20 Lines | #endif | ||||
| * 3. If this vnode is the root of a mounted | * 3. If this vnode is the root of a mounted | ||||
| * filesystem, then replace it with the | * filesystem, then replace it with the | ||||
| * vnode which was mounted on so we take the | * vnode which was mounted on so we take the | ||||
| * .. in the other filesystem. | * .. in the other filesystem. | ||||
| * 4. If the vnode is the top directory of | * 4. If the vnode is the top directory of | ||||
| * the jail or chroot, don't let them out. | * the jail or chroot, don't let them out. | ||||
| */ | */ | ||||
| if (cnp->cn_flags & ISDOTDOT) { | if (cnp->cn_flags & ISDOTDOT) { | ||||
| if (ndp->ni_strictrelative != 0) { | if (ndp->ni_nonrelativeerrno != 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 | ||||
| error = ENOTCAPABLE; | error = ndp->ni_nonrelativeerrno; | ||||
| goto bad; | goto bad; | ||||
| } | } | ||||
| if ((cnp->cn_flags & ISLASTCN) != 0 && | if ((cnp->cn_flags & ISLASTCN) != 0 && | ||||
| (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) { | (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) { | ||||
| error = EINVAL; | error = EINVAL; | ||||
| goto bad; | goto bad; | ||||
| } | } | ||||
| for (;;) { | for (;;) { | ||||
| ▲ Show 20 Lines • Show All 418 Lines • ▼ Show 20 Lines | |||||
| { | { | ||||
| ndp->ni_cnd.cn_nameiop = op; | ndp->ni_cnd.cn_nameiop = op; | ||||
| ndp->ni_cnd.cn_flags = flags; | ndp->ni_cnd.cn_flags = flags; | ||||
| ndp->ni_segflg = segflg; | ndp->ni_segflg = segflg; | ||||
| ndp->ni_dirp = namep; | ndp->ni_dirp = namep; | ||||
| ndp->ni_dirfd = dirfd; | ndp->ni_dirfd = dirfd; | ||||
| ndp->ni_startdir = startdir; | ndp->ni_startdir = startdir; | ||||
| ndp->ni_strictrelative = 0; | ndp->ni_nonrelativeerrno = 0; | ||||
| if (rightsp != NULL) | if (rightsp != NULL) | ||||
| ndp->ni_rightsneeded = *rightsp; | ndp->ni_rightsneeded = *rightsp; | ||||
| else | else | ||||
| cap_rights_init(&ndp->ni_rightsneeded); | cap_rights_init(&ndp->ni_rightsneeded); | ||||
| filecaps_init(&ndp->ni_filecaps); | filecaps_init(&ndp->ni_filecaps); | ||||
| ndp->ni_cnd.cn_thread = td; | ndp->ni_cnd.cn_thread = td; | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 41 Lines • ▼ Show 20 Lines | if (!(flags & NDF_NO_DVP_RELE) && | ||||
| ndp->ni_dvp = NULL; | ndp->ni_dvp = NULL; | ||||
| } | } | ||||
| if (unlock_dvp) | if (unlock_dvp) | ||||
| VOP_UNLOCK(ndp->ni_dvp, 0); | VOP_UNLOCK(ndp->ni_dvp, 0); | ||||
| if (!(flags & NDF_NO_STARTDIR_RELE) && | if (!(flags & NDF_NO_STARTDIR_RELE) && | ||||
| (ndp->ni_cnd.cn_flags & SAVESTART)) { | (ndp->ni_cnd.cn_flags & SAVESTART)) { | ||||
| vrele(ndp->ni_startdir); | vrele(ndp->ni_startdir); | ||||
| ndp->ni_startdir = NULL; | ndp->ni_startdir = NULL; | ||||
| } | |||||
| } | |||||
| void | |||||
| ndrequire_strict_relative_lookups(struct nameidata *ndp, int errnum) | |||||
| { | |||||
| /* | |||||
| * Monotonic ordering of possible field values: | |||||
| * | |||||
| * EPERM - user-level code has requested an O_BENEATH lookup | |||||
| * ENOTCAPABLE - Capsicum demands strict relative lookups | |||||
| * 0 - allow relative lookups | |||||
| * | |||||
| * We can always move up this list but never down. | |||||
| */ | |||||
| KASSERT((errnum == EPERM) || (errnum == ENOTCAPABLE), | |||||
| ("invalid errno (not EPERM or ENOTCAPABLE)")); | |||||
| switch (errnum) { | |||||
| case EPERM: | |||||
| ndp->ni_nonrelativeerrno = errnum; | |||||
| break; | |||||
| case ENOTCAPABLE: | |||||
| if (ndp->ni_nonrelativeerrno != EPERM) { | |||||
| ndp->ni_nonrelativeerrno = errnum; | |||||
| } | |||||
| break; | |||||
| default: | |||||
| KASSERT(false, ("invalid errno for strict relative lookups")); | |||||
| } | } | ||||
| } | } | ||||
| /* | /* | ||||
| * Determine if there is a suitable alternate filename under the specified | * Determine if there is a suitable alternate filename under the specified | ||||
| * prefix for the specified path. If the create flag is set, then the | * prefix for the specified path. If the create flag is set, then the | ||||
| * alternate prefix will be used so long as the parent directory exists. | * alternate prefix will be used so long as the parent directory exists. | ||||
| * This is used by the various compatiblity ABIs so that Linux binaries prefer | * This is used by the various compatiblity ABIs so that Linux binaries prefer | ||||
| ▲ Show 20 Lines • Show All 109 Lines • Show Last 20 Lines | |||||