version 1.237, 2007/02/09 21:55:30 |
version 1.237.2.4, 2007/05/07 10:55:45 |
Line 81 __KERNEL_RCSID(0, "$NetBSD$"); |
|
Line 81 __KERNEL_RCSID(0, "$NetBSD$"); |
|
#include <machine/cpu.h> |
#include <machine/cpu.h> |
#include <machine/reg.h> |
#include <machine/reg.h> |
|
|
|
#include <compat/common/compat_util.h> |
|
|
static int exec_sigcode_map(struct proc *, const struct emul *); |
static int exec_sigcode_map(struct proc *, const struct emul *); |
|
|
#ifdef DEBUG_EXEC |
#ifdef DEBUG_EXEC |
Line 191 const struct emul emul_netbsd = { |
|
Line 193 const struct emul emul_netbsd = { |
|
uvm_default_mapaddr, |
uvm_default_mapaddr, |
NULL, |
NULL, |
sizeof(ucontext_t), |
sizeof(ucontext_t), |
|
startlwp, |
}; |
}; |
|
|
#ifdef LKM |
#ifdef LKM |
Line 239 check_exec(struct lwp *l, struct exec_pa |
|
Line 242 check_exec(struct lwp *l, struct exec_pa |
|
|
|
ndp = epp->ep_ndp; |
ndp = epp->ep_ndp; |
ndp->ni_cnd.cn_nameiop = LOOKUP; |
ndp->ni_cnd.cn_nameiop = LOOKUP; |
ndp->ni_cnd.cn_flags = FOLLOW | LOCKLEAF | SAVENAME; |
ndp->ni_cnd.cn_flags = FOLLOW | LOCKLEAF | SAVENAME | TRYEMULROOT; |
/* first get the vnode */ |
/* first get the vnode */ |
if ((error = namei(ndp)) != 0) |
if ((error = namei(ndp)) != 0) |
return error; |
return error; |
Line 281 check_exec(struct lwp *l, struct exec_pa |
|
Line 284 check_exec(struct lwp *l, struct exec_pa |
|
#endif /* NVERIEXEC > 0 */ |
#endif /* NVERIEXEC > 0 */ |
|
|
#ifdef PAX_SEGVGUARD |
#ifdef PAX_SEGVGUARD |
error = pax_segvguard(l, vp, ndp->ni_cnd.cn_pnbuf, FALSE); |
error = pax_segvguard(l, vp, ndp->ni_cnd.cn_pnbuf, false); |
if (error) |
if (error) |
goto bad2; |
goto bad2; |
#endif /* PAX_SEGVGUARD */ |
#endif /* PAX_SEGVGUARD */ |
Line 307 check_exec(struct lwp *l, struct exec_pa |
|
Line 310 check_exec(struct lwp *l, struct exec_pa |
|
* address space |
* address space |
*/ |
*/ |
error = ENOEXEC; |
error = ENOEXEC; |
for (i = 0; i < nexecs && error != 0; i++) { |
for (i = 0; i < nexecs; i++) { |
int newerror; |
int newerror; |
|
|
epp->ep_esch = execsw[i]; |
epp->ep_esch = execsw[i]; |
newerror = (*execsw[i]->es_makecmds)(l, epp); |
newerror = (*execsw[i]->es_makecmds)(l, epp); |
|
|
|
if (!newerror) { |
|
/* Seems ok: check that entry point is sane */ |
|
if (epp->ep_entry > VM_MAXUSER_ADDRESS) { |
|
error = ENOEXEC; |
|
break; |
|
} |
|
|
|
/* check limits */ |
|
if ((epp->ep_tsize > MAXTSIZ) || |
|
(epp->ep_dsize > (u_quad_t)l->l_proc->p_rlimit |
|
[RLIMIT_DATA].rlim_cur)) { |
|
error = ENOMEM; |
|
break; |
|
} |
|
return 0; |
|
} |
|
|
|
if (epp->ep_emul_root != NULL) { |
|
vrele(epp->ep_emul_root); |
|
epp->ep_emul_root = NULL; |
|
} |
|
if (epp->ep_interp != NULL) { |
|
vrele(epp->ep_interp); |
|
epp->ep_interp = NULL; |
|
} |
|
|
/* make sure the first "interesting" error code is saved. */ |
/* make sure the first "interesting" error code is saved. */ |
if (!newerror || error == ENOEXEC) |
if (error == ENOEXEC) |
error = newerror; |
error = newerror; |
|
|
/* if es_makecmds call was successful, update epp->ep_es */ |
if (epp->ep_flags & EXEC_DESTR) |
if (!newerror && (epp->ep_flags & EXEC_HASES) == 0) |
/* Error from "#!" code, tidied up by recursive call */ |
epp->ep_es = execsw[i]; |
|
|
|
if (epp->ep_flags & EXEC_DESTR && error != 0) |
|
return error; |
return error; |
} |
} |
if (!error) { |
|
/* check that entry point is sane */ |
|
if (epp->ep_entry > VM_MAXUSER_ADDRESS) |
|
error = ENOEXEC; |
|
|
|
/* check limits */ |
|
if ((epp->ep_tsize > MAXTSIZ) || |
|
(epp->ep_dsize > |
|
(u_quad_t)l->l_proc->p_rlimit[RLIMIT_DATA].rlim_cur)) |
|
error = ENOMEM; |
|
|
|
if (!error) |
|
return (0); |
|
} |
|
|
|
/* |
/* |
* free any vmspace-creation commands, |
* free any vmspace-creation commands, |
Line 418 execve1(struct lwp *l, const char *path, |
|
Line 431 execve1(struct lwp *l, const char *path, |
|
ksiginfo_t ksi; |
ksiginfo_t ksi; |
ksiginfoq_t kq; |
ksiginfoq_t kq; |
#ifdef SYSTRACE |
#ifdef SYSTRACE |
int wassugid = ISSET(p->p_flag, P_SUGID); |
int wassugid = ISSET(p->p_flag, PK_SUGID); |
char pathbuf[MAXPATHLEN]; |
char pathbuf[MAXPATHLEN]; |
size_t pathbuflen; |
size_t pathbuflen; |
#endif /* SYSTRACE */ |
#endif /* SYSTRACE */ |
Line 444 execve1(struct lwp *l, const char *path, |
|
Line 457 execve1(struct lwp *l, const char *path, |
|
* see exec_script_makecmds(). |
* see exec_script_makecmds(). |
*/ |
*/ |
#ifdef SYSTRACE |
#ifdef SYSTRACE |
if (ISSET(p->p_flag, P_SYSTRACE)) |
if (ISSET(p->p_flag, PK_SYSTRACE)) |
systrace_execve0(p); |
systrace_execve0(p); |
|
|
error = copyinstr(path, pathbuf, sizeof(pathbuf), |
error = copyinstr(path, pathbuf, sizeof(pathbuf), |
Line 452 execve1(struct lwp *l, const char *path, |
|
Line 465 execve1(struct lwp *l, const char *path, |
|
if (error) |
if (error) |
goto clrflg; |
goto clrflg; |
|
|
NDINIT(&nid, LOOKUP, NOFOLLOW, UIO_SYSSPACE, pathbuf, l); |
NDINIT(&nid, LOOKUP, NOFOLLOW | TRYEMULROOT, UIO_SYSSPACE, pathbuf, l); |
#else |
#else |
NDINIT(&nid, LOOKUP, NOFOLLOW, UIO_USERSPACE, path, l); |
NDINIT(&nid, LOOKUP, NOFOLLOW | TRYEMULROOT, UIO_USERSPACE, path, l); |
#endif /* SYSTRACE */ |
#endif /* SYSTRACE */ |
|
|
/* |
/* |
Line 474 execve1(struct lwp *l, const char *path, |
|
Line 487 execve1(struct lwp *l, const char *path, |
|
pack.ep_vmcmds.evs_used = 0; |
pack.ep_vmcmds.evs_used = 0; |
pack.ep_vap = &attr; |
pack.ep_vap = &attr; |
pack.ep_flags = 0; |
pack.ep_flags = 0; |
|
pack.ep_emul_root = NULL; |
|
pack.ep_interp = NULL; |
|
pack.ep_esch = NULL; |
|
|
#ifdef LKM |
#ifdef LKM |
rw_enter(&exec_lock, RW_READER); |
rw_enter(&exec_lock, RW_READER); |
Line 570 execve1(struct lwp *l, const char *path, |
|
Line 586 execve1(struct lwp *l, const char *path, |
|
|
|
dp = (char *) ALIGN(dp); |
dp = (char *) ALIGN(dp); |
|
|
szsigcode = pack.ep_es->es_emul->e_esigcode - |
szsigcode = pack.ep_esch->es_emul->e_esigcode - |
pack.ep_es->es_emul->e_sigcode; |
pack.ep_esch->es_emul->e_sigcode; |
|
|
/* Now check if args & environ fit into new stack */ |
/* Now check if args & environ fit into new stack */ |
if (pack.ep_flags & EXEC_32) |
if (pack.ep_flags & EXEC_32) |
len = ((argc + envc + 2 + pack.ep_es->es_arglen) * |
len = ((argc + envc + 2 + pack.ep_esch->es_arglen) * |
sizeof(int) + sizeof(int) + dp + STACKGAPLEN + |
sizeof(int) + sizeof(int) + dp + STACKGAPLEN + |
szsigcode + sizeof(struct ps_strings) + STACK_PTHREADSPACE) |
szsigcode + sizeof(struct ps_strings) + STACK_PTHREADSPACE) |
- argp; |
- argp; |
else |
else |
len = ((argc + envc + 2 + pack.ep_es->es_arglen) * |
len = ((argc + envc + 2 + pack.ep_esch->es_arglen) * |
sizeof(char *) + sizeof(int) + dp + STACKGAPLEN + |
sizeof(char *) + sizeof(int) + dp + STACKGAPLEN + |
szsigcode + sizeof(struct ps_strings) + STACK_PTHREADSPACE) |
szsigcode + sizeof(struct ps_strings) + STACK_PTHREADSPACE) |
- argp; |
- argp; |
|
|
|
#ifdef STACKLALIGN /* arm, etc. */ |
|
len = STACKALIGN(len); /* make the stack "safely" aligned */ |
|
#else |
len = ALIGN(len); /* make the stack "safely" aligned */ |
len = ALIGN(len); /* make the stack "safely" aligned */ |
|
#endif |
|
|
if (len > pack.ep_ssize) { /* in effect, compare to initial limit */ |
if (len > pack.ep_ssize) { /* in effect, compare to initial limit */ |
error = ENOMEM; |
error = ENOMEM; |
Line 625 execve1(struct lwp *l, const char *path, |
|
Line 645 execve1(struct lwp *l, const char *path, |
|
|
|
/* Now map address space */ |
/* Now map address space */ |
vm = p->p_vmspace; |
vm = p->p_vmspace; |
vm->vm_taddr = (caddr_t) pack.ep_taddr; |
vm->vm_taddr = (void *)pack.ep_taddr; |
vm->vm_tsize = btoc(pack.ep_tsize); |
vm->vm_tsize = btoc(pack.ep_tsize); |
vm->vm_daddr = (caddr_t) pack.ep_daddr; |
vm->vm_daddr = (void*)pack.ep_daddr; |
vm->vm_dsize = btoc(pack.ep_dsize); |
vm->vm_dsize = btoc(pack.ep_dsize); |
vm->vm_ssize = btoc(pack.ep_ssize); |
vm->vm_ssize = btoc(pack.ep_ssize); |
vm->vm_maxsaddr = (caddr_t) pack.ep_maxsaddr; |
vm->vm_maxsaddr = (void *)pack.ep_maxsaddr; |
vm->vm_minsaddr = (caddr_t) pack.ep_minsaddr; |
vm->vm_minsaddr = (void *)pack.ep_minsaddr; |
|
|
/* create the new process's VM space by running the vmcmds */ |
/* create the new process's VM space by running the vmcmds */ |
#ifdef DIAGNOSTIC |
#ifdef DIAGNOSTIC |
Line 716 execve1(struct lwp *l, const char *path, |
|
Line 736 execve1(struct lwp *l, const char *path, |
|
#endif /* __MACHINE_STACK_GROWS_UP */ |
#endif /* __MACHINE_STACK_GROWS_UP */ |
|
|
/* Now copy argc, args & environ to new stack */ |
/* Now copy argc, args & environ to new stack */ |
error = (*pack.ep_es->es_copyargs)(l, &pack, &arginfo, &stack, argp); |
error = (*pack.ep_esch->es_copyargs)(l, &pack, &arginfo, &stack, argp); |
if (error) { |
if (error) { |
DPRINTF(("execve: copyargs failed %d\n", error)); |
DPRINTF(("execve: copyargs failed %d\n", error)); |
goto exec_abort; |
goto exec_abort; |
Line 752 execve1(struct lwp *l, const char *path, |
|
Line 772 execve1(struct lwp *l, const char *path, |
|
p->p_comm[len] = 0; |
p->p_comm[len] = 0; |
p->p_acflag &= ~AFORK; |
p->p_acflag &= ~AFORK; |
|
|
p->p_flag |= P_EXEC; |
p->p_flag |= PK_EXEC; |
|
|
/* |
/* |
* Stop profiling. |
* Stop profiling. |
Line 768 execve1(struct lwp *l, const char *path, |
|
Line 788 execve1(struct lwp *l, const char *path, |
|
* exited and exec()/exit() are the only places it will be cleared. |
* exited and exec()/exit() are the only places it will be cleared. |
*/ |
*/ |
if ((p->p_sflag & PS_PPWAIT) != 0) { |
if ((p->p_sflag & PS_PPWAIT) != 0) { |
rw_enter(&proclist_lock, RW_READER); |
mutex_enter(&proclist_lock); |
mutex_enter(&p->p_smutex); |
mutex_enter(&p->p_smutex); |
p->p_sflag &= ~PS_PPWAIT; |
p->p_sflag &= ~PS_PPWAIT; |
cv_broadcast(&p->p_pptr->p_waitcv); |
cv_broadcast(&p->p_pptr->p_waitcv); |
mutex_exit(&p->p_smutex); |
mutex_exit(&p->p_smutex); |
rw_exit(&proclist_lock); |
mutex_exit(&proclist_lock); |
} |
} |
|
|
/* |
/* |
Line 793 execve1(struct lwp *l, const char *path, |
|
Line 813 execve1(struct lwp *l, const char *path, |
|
* anything that might block. |
* anything that might block. |
*/ |
*/ |
proc_crmod_enter(); |
proc_crmod_enter(); |
proc_crmod_leave(NULL, NULL, TRUE); |
proc_crmod_leave(NULL, NULL, true); |
|
|
/* Make sure file descriptors 0..2 are in use. */ |
/* Make sure file descriptors 0..2 are in use. */ |
if ((error = fdcheckstd(l)) != 0) { |
if ((error = fdcheckstd(l)) != 0) { |
Line 827 execve1(struct lwp *l, const char *path, |
|
Line 847 execve1(struct lwp *l, const char *path, |
|
kauth_cred_getuid(l->l_cred) && |
kauth_cred_getuid(l->l_cred) && |
kauth_cred_getegid(l->l_cred) == |
kauth_cred_getegid(l->l_cred) == |
kauth_cred_getgid(l->l_cred)) |
kauth_cred_getgid(l->l_cred)) |
p->p_flag &= ~P_SUGID; |
p->p_flag &= ~PK_SUGID; |
} |
} |
|
|
/* |
/* |
Line 871 execve1(struct lwp *l, const char *path, |
|
Line 891 execve1(struct lwp *l, const char *path, |
|
KNOTE(&p->p_klist, NOTE_EXEC); |
KNOTE(&p->p_klist, NOTE_EXEC); |
|
|
/* setup new registers and do misc. setup. */ |
/* setup new registers and do misc. setup. */ |
(*pack.ep_es->es_emul->e_setregs)(l, &pack, (u_long) stack); |
(*pack.ep_esch->es_emul->e_setregs)(l, &pack, (u_long) stack); |
if (pack.ep_es->es_setregs) |
if (pack.ep_esch->es_setregs) |
(*pack.ep_es->es_setregs)(l, &pack, (u_long) stack); |
(*pack.ep_esch->es_setregs)(l, &pack, (u_long) stack); |
|
|
/* map the process's signal trampoline code */ |
/* map the process's signal trampoline code */ |
if (exec_sigcode_map(p, pack.ep_es->es_emul)) { |
if (exec_sigcode_map(p, pack.ep_esch->es_emul)) { |
DPRINTF(("execve: map sigcode failed %d\n", error)); |
DPRINTF(("execve: map sigcode failed %d\n", error)); |
goto exec_abort; |
goto exec_abort; |
} |
} |
|
|
free(pack.ep_hdr, M_EXEC); |
free(pack.ep_hdr, M_EXEC); |
|
|
|
/* The emulation root will usually have been found when we looked |
|
* for the elf interpreter (or similar), if not look now. */ |
|
if (pack.ep_esch->es_emul->e_path != NULL && pack.ep_emul_root == NULL) |
|
emul_find_root(l, &pack); |
|
|
|
/* Any old emulation root got removed by fdcloseexec */ |
|
p->p_cwdi->cwdi_edir = pack.ep_emul_root; |
|
pack.ep_emul_root = NULL; |
|
if (pack.ep_interp != NULL) |
|
vrele(pack.ep_interp); |
|
|
/* |
/* |
* Call emulation specific exec hook. This can setup per-process |
* Call emulation specific exec hook. This can setup per-process |
* p->p_emuldata or do any other per-process stuff an emulation needs. |
* p->p_emuldata or do any other per-process stuff an emulation needs. |
Line 894 execve1(struct lwp *l, const char *path, |
|
Line 925 execve1(struct lwp *l, const char *path, |
|
* resources held previously by this process. |
* resources held previously by this process. |
*/ |
*/ |
if (p->p_emul && p->p_emul->e_proc_exit |
if (p->p_emul && p->p_emul->e_proc_exit |
&& p->p_emul != pack.ep_es->es_emul) |
&& p->p_emul != pack.ep_esch->es_emul) |
(*p->p_emul->e_proc_exit)(p); |
(*p->p_emul->e_proc_exit)(p); |
|
|
/* |
/* |
* Call exec hook. Emulation code may NOT store reference to anything |
* Call exec hook. Emulation code may NOT store reference to anything |
* from &pack. |
* from &pack. |
*/ |
*/ |
if (pack.ep_es->es_emul->e_proc_exec) |
if (pack.ep_esch->es_emul->e_proc_exec) |
(*pack.ep_es->es_emul->e_proc_exec)(p, &pack); |
(*pack.ep_esch->es_emul->e_proc_exec)(p, &pack); |
|
|
/* update p_emul, the old value is no longer needed */ |
/* update p_emul, the old value is no longer needed */ |
p->p_emul = pack.ep_es->es_emul; |
p->p_emul = pack.ep_esch->es_emul; |
|
|
/* ...and the same for p_execsw */ |
/* ...and the same for p_execsw */ |
p->p_execsw = pack.ep_es; |
p->p_execsw = pack.ep_esch; |
|
|
#ifdef __HAVE_SYSCALL_INTERN |
#ifdef __HAVE_SYSCALL_INTERN |
(*p->p_emul->e_syscall_intern)(p); |
(*p->p_emul->e_syscall_intern)(p); |
Line 945 execve1(struct lwp *l, const char *path, |
|
Line 976 execve1(struct lwp *l, const char *path, |
|
p->p_nrlwps--; |
p->p_nrlwps--; |
mutex_exit(&p->p_smutex); |
mutex_exit(&p->p_smutex); |
mutex_exit(&proclist_mutex); |
mutex_exit(&proclist_mutex); |
mi_switch(l, NULL); |
mi_switch(l); |
ksiginfo_queue_drain(&kq); |
ksiginfo_queue_drain(&kq); |
KERNEL_LOCK(l->l_biglocks, l); |
KERNEL_LOCK(l->l_biglocks, l); |
} else { |
} else { |
Line 958 execve1(struct lwp *l, const char *path, |
|
Line 989 execve1(struct lwp *l, const char *path, |
|
|
|
#ifdef SYSTRACE |
#ifdef SYSTRACE |
/* XXXSMP */ |
/* XXXSMP */ |
if (ISSET(p->p_flag, P_SYSTRACE) && |
if (ISSET(p->p_flag, PK_SYSTRACE) && |
wassugid && !ISSET(p->p_flag, P_SUGID)) |
wassugid && !ISSET(p->p_flag, PK_SUGID)) |
systrace_execve1(pathbuf, p); |
systrace_execve1(pathbuf, p); |
#endif /* SYSTRACE */ |
#endif /* SYSTRACE */ |
|
|
Line 982 execve1(struct lwp *l, const char *path, |
|
Line 1013 execve1(struct lwp *l, const char *path, |
|
|
|
freehdr: |
freehdr: |
free(pack.ep_hdr, M_EXEC); |
free(pack.ep_hdr, M_EXEC); |
|
if (pack.ep_emul_root != NULL) |
|
vrele(pack.ep_emul_root); |
|
if (pack.ep_interp != NULL) |
|
vrele(pack.ep_interp); |
|
|
#ifdef SYSTRACE |
#ifdef SYSTRACE |
clrflg: |
clrflg: |
Line 1013 execve1(struct lwp *l, const char *path, |
|
Line 1048 execve1(struct lwp *l, const char *path, |
|
PNBUF_PUT(nid.ni_cnd.cn_pnbuf); |
PNBUF_PUT(nid.ni_cnd.cn_pnbuf); |
uvm_km_free(exec_map, (vaddr_t) argp, NCARGS, UVM_KMF_PAGEABLE); |
uvm_km_free(exec_map, (vaddr_t) argp, NCARGS, UVM_KMF_PAGEABLE); |
free(pack.ep_hdr, M_EXEC); |
free(pack.ep_hdr, M_EXEC); |
|
if (pack.ep_emul_root != NULL) |
|
vrele(pack.ep_emul_root); |
|
if (pack.ep_interp != NULL) |
|
vrele(pack.ep_interp); |
|
|
/* |
/* |
* Acquire the sched-state mutex (exit1() will release it). Since |
* Acquire the sched-state mutex (exit1() will release it). Since |
Line 1044 copyargs(struct lwp *l, struct exec_pack |
|
Line 1083 copyargs(struct lwp *l, struct exec_pack |
|
if ((error = copyout(&argc, cpp++, sizeof(argc))) != 0) |
if ((error = copyout(&argc, cpp++, sizeof(argc))) != 0) |
return error; |
return error; |
|
|
dp = (char *) (cpp + argc + envc + 2 + pack->ep_es->es_arglen); |
dp = (char *) (cpp + argc + envc + 2 + pack->ep_esch->es_arglen); |
sp = argp; |
sp = argp; |
|
|
/* XXX don't copy them out, remap them! */ |
/* XXX don't copy them out, remap them! */ |
Line 1160 emul_unregister(const char *name) |
|
Line 1199 emul_unregister(const char *name) |
|
* emul_unregister() is running quite sendomly, it's better |
* emul_unregister() is running quite sendomly, it's better |
* to do expensive check here than to use any locking. |
* to do expensive check here than to use any locking. |
*/ |
*/ |
rw_enter(&proclist_lock, RW_READER); |
mutex_enter(&proclist_lock); |
for (pd = proclists; pd->pd_list != NULL && !error; pd++) { |
for (pd = proclists; pd->pd_list != NULL && !error; pd++) { |
PROCLIST_FOREACH(ptmp, pd->pd_list) { |
PROCLIST_FOREACH(ptmp, pd->pd_list) { |
if (ptmp->p_emul == it->el_emul) { |
if (ptmp->p_emul == it->el_emul) { |
Line 1169 emul_unregister(const char *name) |
|
Line 1208 emul_unregister(const char *name) |
|
} |
} |
} |
} |
} |
} |
rw_exit(&proclist_lock); |
mutex_exit(&proclist_lock); |
|
|
if (error) |
if (error) |
goto out; |
goto out; |