Changeset View
Changeset View
Standalone View
Standalone View
sys/kern/kern_exec.c
Show First 20 Lines • Show All 369 Lines • ▼ Show 20 Lines | do_execve(struct thread *td, struct image_args *args, struct mac *mac_p) | ||||
struct pargs *oldargs = NULL, *newargs = NULL; | struct pargs *oldargs = NULL, *newargs = NULL; | ||||
struct sigacts *oldsigacts = NULL, *newsigacts = NULL; | struct sigacts *oldsigacts = NULL, *newsigacts = NULL; | ||||
#ifdef KTRACE | #ifdef KTRACE | ||||
struct vnode *tracevp = NULL; | struct vnode *tracevp = NULL; | ||||
struct ucred *tracecred = NULL; | struct ucred *tracecred = NULL; | ||||
#endif | #endif | ||||
struct vnode *oldtextvp = NULL, *newtextvp; | struct vnode *oldtextvp = NULL, *newtextvp; | ||||
int credential_changing; | int credential_changing; | ||||
int textset; | |||||
#ifdef MAC | #ifdef MAC | ||||
struct label *interpvplabel = NULL; | struct label *interpvplabel = NULL; | ||||
int will_transition; | int will_transition; | ||||
#endif | #endif | ||||
#ifdef HWPMC_HOOKS | #ifdef HWPMC_HOOKS | ||||
struct pmckern_procexec pe; | struct pmckern_procexec pe; | ||||
#endif | #endif | ||||
static const char fexecv_proc_title[] = "(fexecv)"; | static const char fexecv_proc_title[] = "(fexecv)"; | ||||
Show All 31 Lines | #endif | ||||
/* | /* | ||||
* Translate the file name. namei() returns a vnode pointer | * Translate the file name. namei() returns a vnode pointer | ||||
* in ni_vp among other things. | * in ni_vp among other things. | ||||
* | * | ||||
* XXXAUDIT: It would be desirable to also audit the name of the | * XXXAUDIT: It would be desirable to also audit the name of the | ||||
* interpreter if this is an interpreted binary. | * interpreter if this is an interpreted binary. | ||||
*/ | */ | ||||
if (args->fname != NULL) { | if (args->fname != NULL) { | ||||
NDINIT(&nd, LOOKUP, ISOPEN | LOCKLEAF | FOLLOW | SAVENAME | NDINIT(&nd, LOOKUP, ISOPEN | LOCKLEAF | LOCKSHARED | FOLLOW | | ||||
| AUDITVNODE1, UIO_SYSSPACE, args->fname, td); | SAVENAME | AUDITVNODE1, UIO_SYSSPACE, args->fname, td); | ||||
} | } | ||||
SDT_PROBE1(proc, , , exec, args->fname); | SDT_PROBE1(proc, , , exec, args->fname); | ||||
interpret: | interpret: | ||||
if (args->fname != NULL) { | if (args->fname != NULL) { | ||||
#ifdef CAPABILITY_MODE | #ifdef CAPABILITY_MODE | ||||
/* | /* | ||||
Show All 16 Lines | #endif | ||||
} else { | } else { | ||||
AUDIT_ARG_FD(args->fd); | AUDIT_ARG_FD(args->fd); | ||||
/* | /* | ||||
* Descriptors opened only with O_EXEC or O_RDONLY are allowed. | * Descriptors opened only with O_EXEC or O_RDONLY are allowed. | ||||
*/ | */ | ||||
error = fgetvp_exec(td, args->fd, &cap_fexecve_rights, &newtextvp); | error = fgetvp_exec(td, args->fd, &cap_fexecve_rights, &newtextvp); | ||||
if (error) | if (error) | ||||
goto exec_fail; | goto exec_fail; | ||||
vn_lock(newtextvp, LK_EXCLUSIVE | LK_RETRY); | vn_lock(newtextvp, LK_SHARED | LK_RETRY); | ||||
AUDIT_ARG_VNODE1(newtextvp); | AUDIT_ARG_VNODE1(newtextvp); | ||||
imgp->vp = newtextvp; | imgp->vp = newtextvp; | ||||
} | } | ||||
/* | /* | ||||
* Check file permissions (also 'opens' file) | * Check file permissions. Also 'opens' file and sets its to | ||||
* text mode. | |||||
markj: Did you mean to write "its vnode"? | |||||
*/ | */ | ||||
error = exec_check_permissions(imgp); | error = exec_check_permissions(imgp); | ||||
if (error) | if (error) | ||||
goto exec_fail_dealloc; | goto exec_fail_dealloc; | ||||
imgp->object = imgp->vp->v_object; | imgp->object = imgp->vp->v_object; | ||||
if (imgp->object != NULL) | if (imgp->object != NULL) | ||||
vm_object_reference(imgp->object); | vm_object_reference(imgp->object); | ||||
/* | |||||
* Set VV_TEXT now so no one can write to the executable while we're | |||||
* activating it. | |||||
* | |||||
* Remember if this was set before and unset it in case this is not | |||||
* actually an executable image. | |||||
*/ | |||||
textset = VOP_IS_TEXT(imgp->vp); | |||||
VOP_SET_TEXT(imgp->vp); | |||||
error = exec_map_first_page(imgp); | error = exec_map_first_page(imgp); | ||||
if (error) | if (error) | ||||
goto exec_fail_dealloc; | goto exec_fail_dealloc; | ||||
imgp->proc->p_osrel = 0; | imgp->proc->p_osrel = 0; | ||||
imgp->proc->p_fctl0 = 0; | imgp->proc->p_fctl0 = 0; | ||||
/* | /* | ||||
▲ Show 20 Lines • Show All 111 Lines • ▼ Show 20 Lines | for (i = 0; error == -1 && execsw[i]; ++i) { | ||||
if (execsw[i]->ex_imgact == NULL || | if (execsw[i]->ex_imgact == NULL || | ||||
execsw[i]->ex_imgact == img_first) { | execsw[i]->ex_imgact == img_first) { | ||||
continue; | continue; | ||||
} | } | ||||
error = (*execsw[i]->ex_imgact)(imgp); | error = (*execsw[i]->ex_imgact)(imgp); | ||||
} | } | ||||
if (error) { | if (error) { | ||||
if (error == -1) { | if (error == -1) | ||||
if (textset == 0) | |||||
VOP_UNSET_TEXT(imgp->vp); | |||||
error = ENOEXEC; | error = ENOEXEC; | ||||
} | |||||
goto exec_fail_dealloc; | goto exec_fail_dealloc; | ||||
} | } | ||||
/* | /* | ||||
* Special interpreter operation, cleanup and loop up to try to | * Special interpreter operation, cleanup and loop up to try to | ||||
* activate the interpreter. | * activate the interpreter. | ||||
*/ | */ | ||||
if (imgp->interpreted) { | if (imgp->interpreted) { | ||||
exec_unmap_first_page(imgp); | exec_unmap_first_page(imgp); | ||||
/* | /* | ||||
* VV_TEXT needs to be unset for scripts. There is a short | * VV_TEXT needs to be unset for scripts. There is a short | ||||
Done Inline ActionsThis comment is stale. markj: This comment is stale. | |||||
* period before we determine that something is a script where | * period before we determine that something is a script where | ||||
* VV_TEXT will be set. The vnode lock is held over this | * VV_TEXT will be set. The vnode lock is held over this | ||||
* entire period so nothing should illegitimately be blocked. | * entire period so nothing should illegitimately be blocked. | ||||
*/ | */ | ||||
VOP_UNSET_TEXT(imgp->vp); | VOP_UNSET_TEXT_SUCCEED(imgp->vp); | ||||
/* free name buffer and old vnode */ | /* free name buffer and old vnode */ | ||||
if (args->fname != NULL) | if (args->fname != NULL) | ||||
NDFREE(&nd, NDF_ONLY_PNBUF); | NDFREE(&nd, NDF_ONLY_PNBUF); | ||||
#ifdef MAC | #ifdef MAC | ||||
mac_execve_interpreter_enter(newtextvp, &interpvplabel); | mac_execve_interpreter_enter(newtextvp, &interpvplabel); | ||||
#endif | #endif | ||||
if (imgp->opened) { | if (imgp->opened) { | ||||
VOP_CLOSE(newtextvp, FREAD, td->td_ucred, td); | VOP_CLOSE(newtextvp, FREAD, td->td_ucred, td); | ||||
▲ Show 20 Lines • Show All 239 Lines • ▼ Show 20 Lines | exec_fail_dealloc: | ||||
if (imgp->firstpage != NULL) | if (imgp->firstpage != NULL) | ||||
exec_unmap_first_page(imgp); | exec_unmap_first_page(imgp); | ||||
if (imgp->vp != NULL) { | if (imgp->vp != NULL) { | ||||
if (args->fname) | if (args->fname) | ||||
NDFREE(&nd, NDF_ONLY_PNBUF); | NDFREE(&nd, NDF_ONLY_PNBUF); | ||||
if (imgp->opened) | if (imgp->opened) | ||||
VOP_CLOSE(imgp->vp, FREAD, td->td_ucred, td); | VOP_CLOSE(imgp->vp, FREAD, td->td_ucred, td); | ||||
VOP_UNSET_TEXT_SUCCEED(imgp->vp); | |||||
if (error != 0) | if (error != 0) | ||||
vput(imgp->vp); | vput(imgp->vp); | ||||
else | else | ||||
VOP_UNLOCK(imgp->vp, 0); | VOP_UNLOCK(imgp->vp, 0); | ||||
} | } | ||||
if (imgp->object != NULL) | if (imgp->object != NULL) | ||||
vm_object_deallocate(imgp->object); | vm_object_deallocate(imgp->object); | ||||
▲ Show 20 Lines • Show All 804 Lines • ▼ Show 20 Lines | |||||
* Return 0 for success or error code on failure. | * Return 0 for success or error code on failure. | ||||
*/ | */ | ||||
int | int | ||||
exec_check_permissions(struct image_params *imgp) | exec_check_permissions(struct image_params *imgp) | ||||
{ | { | ||||
struct vnode *vp = imgp->vp; | struct vnode *vp = imgp->vp; | ||||
struct vattr *attr = imgp->attr; | struct vattr *attr = imgp->attr; | ||||
struct thread *td; | struct thread *td; | ||||
int error, writecount; | int error; | ||||
td = curthread; | td = curthread; | ||||
/* Get file attributes */ | /* Get file attributes */ | ||||
error = VOP_GETATTR(vp, attr, td->td_ucred); | error = VOP_GETATTR(vp, attr, td->td_ucred); | ||||
if (error) | if (error) | ||||
return (error); | return (error); | ||||
Show All 27 Lines | #endif | ||||
*/ | */ | ||||
error = VOP_ACCESS(vp, VEXEC, td->td_ucred, td); | error = VOP_ACCESS(vp, VEXEC, td->td_ucred, td); | ||||
if (error) | if (error) | ||||
return (error); | return (error); | ||||
/* | /* | ||||
* Check number of open-for-writes on the file and deny execution | * Check number of open-for-writes on the file and deny execution | ||||
* if there are any. | * if there are any. | ||||
* | |||||
* Set VV_TEXT now so no one can write to the executable while we're | |||||
Done Inline ActionsThe comment isn't quite right since that flag no longer exists. markj: The comment isn't quite right since that flag no longer exists. | |||||
* activating it. | |||||
* | |||||
* Remember if this was set before and unset it in case this is not | |||||
* actually an executable image. | |||||
*/ | */ | ||||
error = VOP_GET_WRITECOUNT(vp, &writecount); | error = VOP_SET_TEXT(vp); | ||||
if (error != 0) | if (error != 0) | ||||
return (error); | return (error); | ||||
if (writecount != 0) | |||||
return (ETXTBSY); | |||||
/* | /* | ||||
* Call filesystem specific open routine (which does nothing in the | * Call filesystem specific open routine (which does nothing in the | ||||
* general case). | * general case). | ||||
*/ | */ | ||||
error = VOP_OPEN(vp, FREAD, td->td_ucred, td, NULL); | error = VOP_OPEN(vp, FREAD, td->td_ucred, td, NULL); | ||||
if (error == 0) | if (error == 0) | ||||
imgp->opened = 1; | imgp->opened = 1; | ||||
▲ Show 20 Lines • Show All 57 Lines • Show Last 20 Lines |
Did you mean to write "its vnode"?