diff options
| author | chs <chs@NetBSD.org> | 2003-08-24 17:52:28 +0000 |
|---|---|---|
| committer | chs <chs@NetBSD.org> | 2003-08-24 17:52:28 +0000 |
| commit | 939df36e552ea9012b7b0d0d15080f894ebaaaff (patch) | |
| tree | 2c4be187b10b4d03eedeccd43a6ba2359fa195e0 /sys/kern | |
| parent | 4b28d28d7028d98186f61c78a41660eb73edde00 (diff) | |
add support for non-executable mappings (where the hardware allows this)
and make the stack and heap non-executable by default. the changes
fall into two basic catagories:
- pmap and trap-handler changes. these are all MD:
= alpha: we already track per-page execute permission with the (software)
PG_EXEC bit, so just have the trap handler pay attention to it.
= i386: use a new GDT segment for %cs for processes that have no
executable mappings above a certain threshold (currently the
bottom of the stack). track per-page execute permission with
the last unused PTE bit.
= powerpc/ibm4xx: just use the hardware exec bit.
= powerpc/oea: we already track per-page exec bits, but the hardware only
implements non-exec mappings at the segment level. so track the
number of executable mappings in each segment and turn on the no-exec
segment bit iff the count is 0. adjust the trap handler to deal.
= sparc (sun4m): fix our use of the hardware protection bits.
fix the trap handler to recognize text faults.
= sparc64: split the existing unified TSB into data and instruction TSBs,
and only load TTEs into the appropriate TSB(s) for the permissions.
fix the trap handler to check for execute permission.
= not yet implemented: amd64, hppa, sh5
- changes in all the emulations that put a signal trampoline on the stack.
instead, we now put the trampoline into a uvm_aobj and map that into
the process separately.
originally from openbsd, adapted for netbsd by me.
Diffstat (limited to 'sys/kern')
| -rw-r--r-- | sys/kern/exec_subr.c | 11 | ||||
| -rw-r--r-- | sys/kern/kern_exec.c | 91 | ||||
| -rw-r--r-- | sys/kern/kern_resource.c | 6 |
3 files changed, 81 insertions, 27 deletions
diff --git a/sys/kern/exec_subr.c b/sys/kern/exec_subr.c index 0c66a790564..e74eeab987a 100644 --- a/sys/kern/exec_subr.c +++ b/sys/kern/exec_subr.c @@ -1,4 +1,4 @@ -/* $NetBSD: exec_subr.c,v 1.39 2003/08/21 15:17:03 yamt Exp $ */ +/* $NetBSD: exec_subr.c,v 1.40 2003/08/24 17:52:47 chs Exp $ */ /* * Copyright (c) 1993, 1994, 1996 Christopher G. Demetriou @@ -31,7 +31,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: exec_subr.c,v 1.39 2003/08/21 15:17:03 yamt Exp $"); +__KERNEL_RCSID(0, "$NetBSD: exec_subr.c,v 1.40 2003/08/24 17:52:47 chs Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -121,7 +121,7 @@ kill_vmcmds(struct exec_vmcmd_set *evsp) for (i = 0; i < evsp->evs_used; i++) { vcp = &evsp->evs_cmds[i]; - if (vcp->ev_vp != NULLVP) + if (vcp->ev_vp != NULL) vrele(vcp->ev_vp); } evsp->evs_used = evsp->evs_cnt = 0; @@ -344,12 +344,11 @@ exec_setup_stack(struct proc *p, struct exec_package *epp) access_size), noaccess_size); if (noaccess_size > 0) { NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero, noaccess_size, - noaccess_linear_min, NULLVP, 0, VM_PROT_NONE); + noaccess_linear_min, NULL, 0, VM_PROT_NONE); } KASSERT(access_size > 0); NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero, access_size, - access_linear_min, NULLVP, 0, - VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE); + access_linear_min, NULL, 0, VM_PROT_READ | VM_PROT_WRITE); return 0; } diff --git a/sys/kern/kern_exec.c b/sys/kern/kern_exec.c index 7343bd51d14..4e1656d8ca4 100644 --- a/sys/kern/kern_exec.c +++ b/sys/kern/kern_exec.c @@ -1,4 +1,4 @@ -/* $NetBSD: kern_exec.c,v 1.170 2003/07/16 22:42:48 dsl Exp $ */ +/* $NetBSD: kern_exec.c,v 1.171 2003/08/24 17:52:47 chs Exp $ */ /*- * Copyright (C) 1993, 1994, 1996 Christopher G. Demetriou @@ -33,7 +33,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: kern_exec.c,v 1.170 2003/07/16 22:42:48 dsl Exp $"); +__KERNEL_RCSID(0, "$NetBSD: kern_exec.c,v 1.171 2003/08/24 17:52:47 chs Exp $"); #include "opt_ktrace.h" #include "opt_syscall_debug.h" @@ -68,6 +68,8 @@ __KERNEL_RCSID(0, "$NetBSD: kern_exec.c,v 1.170 2003/07/16 22:42:48 dsl Exp $"); #include <machine/cpu.h> #include <machine/reg.h> +static int exec_sigcode_map(struct proc *, const struct emul *); + #ifdef DEBUG_EXEC #define DPRINTF(a) uprintf a #else @@ -129,6 +131,8 @@ void syscall_intern(struct proc *); void syscall(void); #endif +struct uvm_object *emul_netbsd_object; + const struct emul emul_netbsd = { "netbsd", NULL, /* emulation path */ @@ -148,6 +152,7 @@ const struct emul emul_netbsd = { trapsignal, sigcode, esigcode, + &emul_netbsd_object, setregs, NULL, NULL, @@ -629,7 +634,7 @@ sys_execve(struct lwp *l, void *v, register_t *retval) * it's easy to decrement the stack pointer a little bit to * allocate the space for these few words and pass the new * stack pointer to _rtld. When the stack grows up, however, - * a few words before argc is part of the signal trampoline, + * a few words before argc is part of the signal trampoline, XXX * so we have a problem. * * Instead of changing how _rtld works, we take the easy way @@ -664,21 +669,6 @@ sys_execve(struct lwp *l, void *v, register_t *retval) goto exec_abort; } - /* copy out the process's signal trampoline code */ - if (szsigcode) { - p->p_sigctx.ps_sigcode = STACK_ALLOC(STACK_MAX(p->p_psstr, - sizeof(struct ps_strings)), szsigcode); - if ((error = copyout((char *)pack.ep_es->es_emul->e_sigcode, - p->p_sigctx.ps_sigcode, szsigcode)) != 0) { - DPRINTF(("execve: sig trampoline copyout failed\n")); - goto exec_abort; - } -#ifdef PMAP_NEED_PROCWR - /* This is code. Let the pmap do what is needed. */ - pmap_procwr(p, (vaddr_t)p->p_sigctx.ps_sigcode, szsigcode); -#endif - } - stopprofclock(p); /* stop profiling */ fdcloseexec(p); /* handle close on exec */ execsigs(p); /* reset catched signals */ @@ -766,6 +756,10 @@ sys_execve(struct lwp *l, void *v, register_t *retval) if (pack.ep_es->es_setregs) (*pack.ep_es->es_setregs)(l, &pack, (u_long) stack); + /* map the process's signal trampoline code */ + if (exec_sigcode_map(p, pack.ep_es->es_emul)) + goto exec_abort; + if (p->p_flag & P_TRACED) psignal(p, SIGTRAP); @@ -1271,3 +1265,64 @@ exec_init(int init_boot) } #endif /* !LKM */ + +static int +exec_sigcode_map(struct proc *p, const struct emul *e) +{ + vaddr_t va; + vsize_t sz; + int error; + struct uvm_object *uobj; + + if (e->e_sigobject == NULL) { + return 0; + } + + /* + * If we don't have a sigobject for this emulation, create one. + * + * sigobject is an anonymous memory object (just like SYSV shared + * memory) that we keep a permanent reference to and that we map + * in all processes that need this sigcode. The creation is simple, + * we create an object, add a permanent reference to it, map it in + * kernel space, copy out the sigcode to it and unmap it. + * The we map it with PROT_READ|PROT_EXEC into the process just + * the way sys_mmap would map it. + */ + + sz = (vaddr_t)e->e_esigcode - (vaddr_t)e->e_sigcode; + uobj = *e->e_sigobject; + if (uobj == NULL) { + uobj = uao_create(sz, 0); + uao_reference(uobj); + va = vm_map_min(kernel_map); + if ((error = uvm_map(kernel_map, &va, round_page(sz), + uobj, 0, 0, + UVM_MAPFLAG(UVM_PROT_RW, UVM_PROT_RW, + UVM_INH_SHARE, UVM_ADV_RANDOM, 0)))) { + printf("kernel mapping failed %d\n", error); + (*uobj->pgops->pgo_detach)(uobj); + return (error); + } + memcpy((void *)va, e->e_sigcode, sz); +#ifdef PMAP_NEED_PROCWR + pmap_procwr(&proc0, va, sz); +#endif + uvm_unmap(kernel_map, va, va + round_page(sz)); + *e->e_sigobject = uobj; + } + + /* Just a hint to uvm_mmap where to put it. */ + va = round_page((vaddr_t)p->p_vmspace->vm_daddr + MAXDSIZ); + (*uobj->pgops->pgo_reference)(uobj); + error = uvm_map(&p->p_vmspace->vm_map, &va, round_page(sz), + uobj, 0, 0, + UVM_MAPFLAG(UVM_PROT_RX, UVM_PROT_RX, UVM_INH_SHARE, + UVM_ADV_RANDOM, 0)); + if (error) { + (*uobj->pgops->pgo_detach)(uobj); + return (error); + } + p->p_sigctx.ps_sigcode = (void *)va; + return (0); +} diff --git a/sys/kern/kern_resource.c b/sys/kern/kern_resource.c index d29582845eb..aa912d3b10b 100644 --- a/sys/kern/kern_resource.c +++ b/sys/kern/kern_resource.c @@ -1,4 +1,4 @@ -/* $NetBSD: kern_resource.c,v 1.72 2003/08/07 16:31:48 agc Exp $ */ +/* $NetBSD: kern_resource.c,v 1.73 2003/08/24 17:52:47 chs Exp $ */ /*- * Copyright (c) 1982, 1986, 1991, 1993 @@ -37,7 +37,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: kern_resource.c,v 1.72 2003/08/07 16:31:48 agc Exp $"); +__KERNEL_RCSID(0, "$NetBSD: kern_resource.c,v 1.73 2003/08/24 17:52:47 chs Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -323,7 +323,7 @@ dosetrlimit(p, cred, which, limp) vm_prot_t prot; if (limp->rlim_cur > alimp->rlim_cur) { - prot = VM_PROT_ALL; + prot = VM_PROT_READ | VM_PROT_WRITE; size = limp->rlim_cur - alimp->rlim_cur; addr = USRSTACK - limp->rlim_cur; } else { |
