summaryrefslogtreecommitdiff
path: root/sys/kern
diff options
context:
space:
mode:
authorchs <chs@NetBSD.org>2003-08-24 17:52:28 +0000
committerchs <chs@NetBSD.org>2003-08-24 17:52:28 +0000
commit939df36e552ea9012b7b0d0d15080f894ebaaaff (patch)
tree2c4be187b10b4d03eedeccd43a6ba2359fa195e0 /sys/kern
parent4b28d28d7028d98186f61c78a41660eb73edde00 (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.c11
-rw-r--r--sys/kern/kern_exec.c91
-rw-r--r--sys/kern/kern_resource.c6
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 {