diff options
author | Luiz Otavio O Souza <luiz@netgate.com> | 2016-06-30 13:24:42 -0500 |
---|---|---|
committer | Luiz Otavio O Souza <luiz@netgate.com> | 2016-06-30 13:24:42 -0500 |
commit | 9d5ffb47ff56597309eb2939cc97b1df4d616797 (patch) | |
tree | b34fd92dce8092bb4cb58c875caabd93e1fece39 /sys/kern/kern_exec.c | |
parent | 1fc6b0207cc2f3cce33817706603caa41a9de24d (diff) | |
parent | 13295f52fb5936b237a994e75311fe18612c73c4 (diff) | |
download | FreeBSD-src-9d5ffb47ff56597309eb2939cc97b1df4d616797.zip FreeBSD-src-9d5ffb47ff56597309eb2939cc97b1df4d616797.tar.gz |
Merge remote-tracking branch 'origin/stable/10' into devel
Diffstat (limited to 'sys/kern/kern_exec.c')
-rw-r--r-- | sys/kern/kern_exec.c | 338 |
1 files changed, 174 insertions, 164 deletions
diff --git a/sys/kern/kern_exec.c b/sys/kern/kern_exec.c index 47ea9b0..eeb8369 100644 --- a/sys/kern/kern_exec.c +++ b/sys/kern/kern_exec.c @@ -96,9 +96,9 @@ dtrace_execexit_func_t dtrace_fasttrap_exec; #endif SDT_PROVIDER_DECLARE(proc); -SDT_PROBE_DEFINE1(proc, kernel, , exec, "char *"); -SDT_PROBE_DEFINE1(proc, kernel, , exec__failure, "int"); -SDT_PROBE_DEFINE1(proc, kernel, , exec__success, "char *"); +SDT_PROBE_DEFINE1(proc, , , exec, "char *"); +SDT_PROBE_DEFINE1(proc, , , exec__failure, "int"); +SDT_PROBE_DEFINE1(proc, , , exec__success, "char *"); MALLOC_DEFINE(M_PARGS, "proc-args", "Process arguments"); @@ -359,7 +359,7 @@ do_execve(td, args, mac_p) { struct proc *p = td->td_proc; struct nameidata nd; - struct ucred *newcred = NULL, *oldcred; + struct ucred *oldcred; struct uidinfo *euip = NULL; register_t *stack_base; int error, i; @@ -367,12 +367,12 @@ do_execve(td, args, mac_p) struct vattr attr; int (*img_first)(struct image_params *); struct pargs *oldargs = NULL, *newargs = NULL; - struct sigacts *oldsigacts, *newsigacts; + struct sigacts *oldsigacts = NULL, *newsigacts = NULL; #ifdef KTRACE struct vnode *tracevp = NULL; struct ucred *tracecred = NULL; #endif - struct vnode *textvp = NULL, *binvp = NULL; + struct vnode *oldtextvp = NULL, *newtextvp; cap_rights_t rights; int credential_changing; int textset; @@ -407,6 +407,7 @@ do_execve(td, args, mac_p) imgp->proc = p; imgp->attr = &attr; imgp->args = args; + oldcred = p->p_ucred; #ifdef MAC error = mac_execve_enter(imgp, mac_p); @@ -416,7 +417,7 @@ do_execve(td, args, mac_p) /* * Translate the file name. namei() returns a vnode pointer - * in ni_vp amoung other things. + * in ni_vp among other things. * * XXXAUDIT: It would be desirable to also audit the name of the * interpreter if this is an interpreted binary. @@ -426,7 +427,7 @@ do_execve(td, args, mac_p) | AUDITVNODE1, UIO_SYSSPACE, args->fname, td); } - SDT_PROBE1(proc, kernel, , exec, args->fname); + SDT_PROBE1(proc, , , exec, args->fname); interpret: if (args->fname != NULL) { @@ -446,20 +447,20 @@ interpret: if (error) goto exec_fail; - binvp = nd.ni_vp; - imgp->vp = binvp; + newtextvp = nd.ni_vp; + imgp->vp = newtextvp; } else { AUDIT_ARG_FD(args->fd); /* * Descriptors opened only with O_EXEC or O_RDONLY are allowed. */ error = fgetvp_exec(td, args->fd, - cap_rights_init(&rights, CAP_FEXECVE), &binvp); + cap_rights_init(&rights, CAP_FEXECVE), &newtextvp); if (error) goto exec_fail; - vn_lock(binvp, LK_EXCLUSIVE | LK_RETRY); - AUDIT_ARG_VNODE1(binvp); - imgp->vp = binvp; + vn_lock(newtextvp, LK_EXCLUSIVE | LK_RETRY); + AUDIT_ARG_VNODE1(newtextvp); + imgp->vp = newtextvp; } /* @@ -488,6 +489,100 @@ interpret: goto exec_fail_dealloc; imgp->proc->p_osrel = 0; + + /* + * Implement image setuid/setgid. + * + * Determine new credentials before attempting image activators + * so that it can be used by process_exec handlers to determine + * credential/setid changes. + * + * Don't honor setuid/setgid if the filesystem prohibits it or if + * the process is being traced. + * + * We disable setuid/setgid/etc in capability mode on the basis + * that most setugid applications are not written with that + * environment in mind, and will therefore almost certainly operate + * incorrectly. In principle there's no reason that setugid + * applications might not be useful in capability mode, so we may want + * to reconsider this conservative design choice in the future. + * + * XXXMAC: For the time being, use NOSUID to also prohibit + * transitions on the file system. + */ + credential_changing = 0; + credential_changing |= (attr.va_mode & S_ISUID) && + oldcred->cr_uid != attr.va_uid; + credential_changing |= (attr.va_mode & S_ISGID) && + oldcred->cr_gid != attr.va_gid; +#ifdef MAC + will_transition = mac_vnode_execve_will_transition(oldcred, imgp->vp, + interpvplabel, imgp); + credential_changing |= will_transition; +#endif + + if (credential_changing && +#ifdef CAPABILITY_MODE + ((oldcred->cr_flags & CRED_FLAG_CAPMODE) == 0) && +#endif + (imgp->vp->v_mount->mnt_flag & MNT_NOSUID) == 0 && + (p->p_flag & P_TRACED) == 0) { + imgp->credential_setid = true; + VOP_UNLOCK(imgp->vp, 0); + imgp->newcred = crdup(oldcred); + if (attr.va_mode & S_ISUID) { + euip = uifind(attr.va_uid); + change_euid(imgp->newcred, euip); + } + vn_lock(imgp->vp, LK_EXCLUSIVE | LK_RETRY); + if (attr.va_mode & S_ISGID) + change_egid(imgp->newcred, attr.va_gid); + /* + * Implement correct POSIX saved-id behavior. + * + * XXXMAC: Note that the current logic will save the + * uid and gid if a MAC domain transition occurs, even + * though maybe it shouldn't. + */ + change_svuid(imgp->newcred, imgp->newcred->cr_uid); + change_svgid(imgp->newcred, imgp->newcred->cr_gid); + } else { + /* + * Implement correct POSIX saved-id behavior. + * + * XXX: It's not clear that the existing behavior is + * POSIX-compliant. A number of sources indicate that the + * saved uid/gid should only be updated if the new ruid is + * not equal to the old ruid, or the new euid is not equal + * to the old euid and the new euid is not equal to the old + * ruid. The FreeBSD code always updates the saved uid/gid. + * Also, this code uses the new (replaced) euid and egid as + * the source, which may or may not be the right ones to use. + */ + if (oldcred->cr_svuid != oldcred->cr_uid || + oldcred->cr_svgid != oldcred->cr_gid) { + VOP_UNLOCK(imgp->vp, 0); + imgp->newcred = crdup(oldcred); + vn_lock(imgp->vp, LK_EXCLUSIVE | LK_RETRY); + change_svuid(imgp->newcred, imgp->newcred->cr_uid); + change_svgid(imgp->newcred, imgp->newcred->cr_gid); + } + } + /* The new credentials are installed into the process later. */ + + /* + * Do the best to calculate the full path to the image file. + */ + if (args->fname != NULL && args->fname[0] == '/') + imgp->execpath = args->fname; + else { + VOP_UNLOCK(imgp->vp, 0); + if (vn_fullpath(td, imgp->vp, &imgp->execpath, + &imgp->freepath) != 0) + imgp->execpath = args->fname; + vn_lock(imgp->vp, LK_EXCLUSIVE | LK_RETRY); + } + /* * If the current process has a special image activator it * wants to try first, call it. For example, emulating shell @@ -536,15 +631,23 @@ interpret: if (args->fname != NULL) NDFREE(&nd, NDF_ONLY_PNBUF); #ifdef MAC - mac_execve_interpreter_enter(binvp, &interpvplabel); + mac_execve_interpreter_enter(newtextvp, &interpvplabel); #endif if (imgp->opened) { - VOP_CLOSE(binvp, FREAD, td->td_ucred, td); + VOP_CLOSE(newtextvp, FREAD, td->td_ucred, td); imgp->opened = 0; } - vput(binvp); + vput(newtextvp); vm_object_deallocate(imgp->object); imgp->object = NULL; + imgp->credential_setid = false; + if (imgp->newcred != NULL) { + crfree(imgp->newcred); + imgp->newcred = NULL; + } + imgp->execpath = NULL; + free(imgp->freepath, M_TEMP); + imgp->freepath = NULL; /* set new name to that of the interpreter */ NDINIT(&nd, LOOKUP, LOCKLEAF | FOLLOW | SAVENAME, UIO_SYSSPACE, imgp->interpreter_name, td); @@ -558,14 +661,6 @@ interpret: */ VOP_UNLOCK(imgp->vp, 0); - /* - * Do the best to calculate the full path to the image file. - */ - if (imgp->auxargs != NULL && - ((args->fname != NULL && args->fname[0] == '/') || - vn_fullpath(td, imgp->vp, &imgp->execpath, &imgp->freepath) != 0)) - imgp->execpath = args->fname; - if (disallow_high_osrel && P_OSREL_MAJOR(p->p_osrel) > P_OSREL_MAJOR(__FreeBSD_version)) { error = ENOEXEC; @@ -611,11 +706,6 @@ interpret: bcopy(imgp->args->begin_argv, newargs->ar_args, i); } - vn_lock(imgp->vp, LK_SHARED | LK_RETRY); - - /* Get a reference to the vnode prior to locking the proc */ - VREF(binvp); - /* * For security and other reasons, signal handlers cannot * be shared after an exec. The new process gets a copy of the old @@ -626,15 +716,13 @@ interpret: oldsigacts = p->p_sigacts; newsigacts = sigacts_alloc(); sigacts_copy(newsigacts, oldsigacts); - } else { - oldsigacts = NULL; - newsigacts = NULL; /* satisfy gcc */ } + vn_lock(imgp->vp, LK_SHARED | LK_RETRY); + PROC_LOCK(p); if (oldsigacts) p->p_sigacts = newsigacts; - oldcred = p->p_ucred; /* Stop profiling */ stopprofclock(p); @@ -646,7 +734,7 @@ interpret: if (args->fname) bcopy(nd.ni_cnd.cn_nameptr, p->p_comm, min(nd.ni_cnd.cn_namelen, MAXCOMLEN)); - else if (vn_commname(binvp, p->p_comm, sizeof(p->p_comm)) != 0) + else if (vn_commname(newtextvp, p->p_comm, sizeof(p->p_comm)) != 0) bcopy(fexecv_proc_title, p->p_comm, sizeof(fexecv_proc_title)); bcopy(p->p_comm, td->td_name, sizeof(td->td_name)); #ifdef KTR @@ -666,38 +754,9 @@ interpret: } /* - * Implement image setuid/setgid. - * - * Don't honor setuid/setgid if the filesystem prohibits it or if - * the process is being traced. - * - * We disable setuid/setgid/etc in compatibility mode on the basis - * that most setugid applications are not written with that - * environment in mind, and will therefore almost certainly operate - * incorrectly. In principle there's no reason that setugid - * applications might not be useful in capability mode, so we may want - * to reconsider this conservative design choice in the future. - * - * XXXMAC: For the time being, use NOSUID to also prohibit - * transitions on the file system. + * Implement image setuid/setgid installation. */ - credential_changing = 0; - credential_changing |= (attr.va_mode & S_ISUID) && oldcred->cr_uid != - attr.va_uid; - credential_changing |= (attr.va_mode & S_ISGID) && oldcred->cr_gid != - attr.va_gid; -#ifdef MAC - will_transition = mac_vnode_execve_will_transition(oldcred, imgp->vp, - interpvplabel, imgp); - credential_changing |= will_transition; -#endif - - if (credential_changing && -#ifdef CAPABILITY_MODE - ((oldcred->cr_flags & CRED_FLAG_CAPMODE) == 0) && -#endif - (imgp->vp->v_mount->mnt_flag & MNT_NOSUID) == 0 && - (p->p_flag & P_TRACED) == 0) { + if (imgp->credential_setid) { /* * Turn off syscall tracing for set-id programs, except for * root. Record any set-id flags first to make sure that @@ -723,70 +782,36 @@ interpret: VOP_UNLOCK(imgp->vp, 0); setugidsafety(td); error = fdcheckstd(td); - if (error != 0) - goto done1; - newcred = crdup(oldcred); - euip = uifind(attr.va_uid); vn_lock(imgp->vp, LK_SHARED | LK_RETRY); + if (error != 0) + goto exec_fail_dealloc; PROC_LOCK(p); - /* - * Set the new credentials. - */ - if (attr.va_mode & S_ISUID) - change_euid(newcred, euip); - if (attr.va_mode & S_ISGID) - change_egid(newcred, attr.va_gid); #ifdef MAC if (will_transition) { - mac_vnode_execve_transition(oldcred, newcred, imgp->vp, - interpvplabel, imgp); + mac_vnode_execve_transition(oldcred, imgp->newcred, + imgp->vp, interpvplabel, imgp); } #endif - /* - * Implement correct POSIX saved-id behavior. - * - * XXXMAC: Note that the current logic will save the - * uid and gid if a MAC domain transition occurs, even - * though maybe it shouldn't. - */ - change_svuid(newcred, newcred->cr_uid); - change_svgid(newcred, newcred->cr_gid); - p->p_ucred = newcred; } else { if (oldcred->cr_uid == oldcred->cr_ruid && oldcred->cr_gid == oldcred->cr_rgid) p->p_flag &= ~P_SUGID; - /* - * Implement correct POSIX saved-id behavior. - * - * XXX: It's not clear that the existing behavior is - * POSIX-compliant. A number of sources indicate that the - * saved uid/gid should only be updated if the new ruid is - * not equal to the old ruid, or the new euid is not equal - * to the old euid and the new euid is not equal to the old - * ruid. The FreeBSD code always updates the saved uid/gid. - * Also, this code uses the new (replaced) euid and egid as - * the source, which may or may not be the right ones to use. - */ - if (oldcred->cr_svuid != oldcred->cr_uid || - oldcred->cr_svgid != oldcred->cr_gid) { - PROC_UNLOCK(p); - VOP_UNLOCK(imgp->vp, 0); - newcred = crdup(oldcred); - vn_lock(imgp->vp, LK_SHARED | LK_RETRY); - PROC_LOCK(p); - change_svuid(newcred, newcred->cr_uid); - change_svgid(newcred, newcred->cr_gid); - p->p_ucred = newcred; - } + } + /* + * Set the new credentials. + */ + if (imgp->newcred != NULL) { + proc_set_cred(p, imgp->newcred); + crfree(oldcred); + oldcred = NULL; } /* - * Store the vp for use in procfs. This vnode was referenced prior - * to locking the proc lock. + * Store the vp for use in procfs. This vnode was referenced by namei + * or fgetvp_exec. */ - textvp = p->p_textvp; - p->p_textvp = binvp; + oldtextvp = p->p_textvp; + p->p_textvp = newtextvp; #ifdef KDTRACE_HOOKS /* @@ -848,42 +873,9 @@ interpret: vfs_mark_atime(imgp->vp, td->td_ucred); - SDT_PROBE1(proc, kernel, , exec__success, args->fname); - - VOP_UNLOCK(imgp->vp, 0); -done1: - /* - * Free any resources malloc'd earlier that we didn't use. - */ - if (euip != NULL) - uifree(euip); - if (newcred != NULL) - crfree(oldcred); - - /* - * Handle deferred decrement of ref counts. - */ - if (textvp != NULL) - vrele(textvp); - if (binvp && error != 0) - vrele(binvp); -#ifdef KTRACE - if (tracevp != NULL) - vrele(tracevp); - if (tracecred != NULL) - crfree(tracecred); -#endif - vn_lock(imgp->vp, LK_SHARED | LK_RETRY); - pargs_drop(oldargs); - pargs_drop(newargs); - if (oldsigacts != NULL) - sigacts_free(oldsigacts); + SDT_PROBE1(proc, , , exec__success, args->fname); exec_fail_dealloc: - - /* - * free various allocated resources - */ if (imgp->firstpage != NULL) exec_unmap_first_page(imgp); @@ -892,7 +884,10 @@ exec_fail_dealloc: NDFREE(&nd, NDF_ONLY_PNBUF); if (imgp->opened) VOP_CLOSE(imgp->vp, FREAD, td->td_ucred, td); - vput(imgp->vp); + if (error != 0) + vput(imgp->vp); + else + VOP_UNLOCK(imgp->vp, 0); } if (imgp->object != NULL) @@ -910,24 +905,43 @@ exec_fail_dealloc: * the S_EXEC bit set. */ STOPEVENT(p, S_EXEC, 0); - goto done2; - } - + } else { exec_fail: - /* we're done here, clear P_INEXEC */ - PROC_LOCK(p); - p->p_flag &= ~P_INEXEC; - PROC_UNLOCK(p); + /* we're done here, clear P_INEXEC */ + PROC_LOCK(p); + p->p_flag &= ~P_INEXEC; + PROC_UNLOCK(p); - SDT_PROBE1(proc, kernel, , exec__failure, error); + SDT_PROBE1(proc, , , exec__failure, error); + } + + if (imgp->newcred != NULL && oldcred != NULL) + crfree(imgp->newcred); -done2: #ifdef MAC mac_execve_exit(imgp); mac_execve_interpreter_exit(interpvplabel); #endif exec_free_args(args); + /* + * Handle deferred decrement of ref counts. + */ + if (oldtextvp != NULL) + vrele(oldtextvp); +#ifdef KTRACE + if (tracevp != NULL) + vrele(tracevp); + if (tracecred != NULL) + crfree(tracecred); +#endif + pargs_drop(oldargs); + pargs_drop(newargs); + if (oldsigacts != NULL) + sigacts_free(oldsigacts); + if (euip != NULL) + uifree(euip); + if (error && imgp->vmspace_destroyed) { /* sorry, no more process anymore. exit gracefully */ exit1(td, W_EXITCODE(0, SIGABRT)); @@ -1500,8 +1514,6 @@ exec_register(execsw_arg) for (es = execsw; *es; es++) count++; newexecsw = malloc(count * sizeof(*es), M_TEMP, M_WAITOK); - if (newexecsw == NULL) - return (ENOMEM); xs = newexecsw; if (execsw) for (es = execsw; *es; es++) @@ -1534,8 +1546,6 @@ exec_unregister(execsw_arg) if (*es != execsw_arg) count++; newexecsw = malloc(count * sizeof(*es), M_TEMP, M_WAITOK); - if (newexecsw == NULL) - return (ENOMEM); xs = newexecsw; for (es = execsw; *es; es++) if (*es != execsw_arg) |