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 |