summaryrefslogtreecommitdiffstats
path: root/sys/kern/kern_exec.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/kern/kern_exec.c')
-rw-r--r--sys/kern/kern_exec.c81
1 files changed, 62 insertions, 19 deletions
diff --git a/sys/kern/kern_exec.c b/sys/kern/kern_exec.c
index fd12717ce6a..7fb2276bb39 100644
--- a/sys/kern/kern_exec.c
+++ b/sys/kern/kern_exec.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kern_exec.c,v 1.67 2002/05/02 00:36:04 millert Exp $ */
+/* $OpenBSD: kern_exec.c,v 1.68 2002/07/20 19:24:57 art Exp $ */
/* $NetBSD: kern_exec.c,v 1.75 1996/02/09 18:59:28 christos Exp $ */
/*-
@@ -66,6 +66,11 @@
#include <dev/rndvar.h>
/*
+ * Map the shared signal code.
+ */
+int exec_sigcode_map(struct proc *, struct emul *);
+
+/*
* stackgap_random specifies if the stackgap should have a random size added
* to it. Must be a n^2. If non-zero, the stack gap will be calculated as:
* (arc4random() * ALIGNBYTES) & (stackgap_random - 1) + STACKGAPLEN.
@@ -246,7 +251,6 @@ sys_execve(p, v, retval)
struct ps_strings arginfo;
struct vmspace *vm = p->p_vmspace;
char **tmpfap;
- int szsigcode;
extern struct emul emul_native;
/*
@@ -365,15 +369,12 @@ sys_execve(p, v, retval)
dp = (char *)ALIGN(dp);
- szsigcode = pack.ep_emul->e_esigcode - pack.ep_emul->e_sigcode;
-
sgap = STACKGAPLEN;
if (stackgap_random != 0)
sgap += (arc4random() * ALIGNBYTES) & (stackgap_random - 1);
/* Now check if args & environ fit into new stack */
len = ((argc + envc + 2 + pack.ep_emul->e_arglen) * sizeof(char *) +
- sizeof(long) + dp + sgap + szsigcode +
- sizeof(struct ps_strings)) - argp;
+ sizeof(long) + dp + sgap + sizeof(struct ps_strings)) - argp;
len = ALIGN(len); /* make the stack "safely" aligned */
@@ -424,8 +425,8 @@ sys_execve(p, v, retval)
arginfo.ps_nenvstr = envc;
#ifdef MACHINE_STACK_GROWS_UP
- stack = (char *)USRSTACK + sizeof(arginfo) + szsigcode;
- slen = len - sizeof(arginfo) - szsigcode;
+ stack = (char *)USRSTACK + sizeof(arginfo);
+ slen = len - sizeof(arginfo);
#else
stack = (char *)(USRSTACK - len);
#endif
@@ -437,17 +438,6 @@ sys_execve(p, v, retval)
if (copyout(&arginfo, (char *)PS_STRINGS, sizeof(arginfo)))
goto exec_abort;
- /* copy out the process's signal trampoline code */
-#ifdef MACHINE_STACK_GROWS_UP
- if (szsigcode && copyout((char *)pack.ep_emul->e_sigcode,
- ((char *)PS_STRINGS) + sizeof(arginfo), szsigcode))
- goto exec_abort;
-#else
- if (szsigcode && copyout((char *)pack.ep_emul->e_sigcode,
- ((char *)PS_STRINGS) - szsigcode, szsigcode))
- goto exec_abort;
-#endif
-
stopprofclock(p); /* stop profiling */
fdcloseexec(p); /* handle close on exec */
execsigs(p); /* reset catched signals */
@@ -607,6 +597,10 @@ sys_execve(p, v, retval)
(*pack.ep_emul->e_setregs)(p, &pack, (u_long)stack, retval);
#endif
+ /* map the process's signal trampoline code */
+ if (exec_sigcode_map(p, pack.ep_emul))
+ goto exec_abort;
+
if (p->p_flag & P_TRACED)
psignal(p, SIGTRAP);
@@ -708,3 +702,52 @@ copyargs(pack, arginfo, stack, argp)
return (cpp);
}
+
+int
+exec_sigcode_map(struct proc *p, struct emul *e)
+{
+ vsize_t sz;
+
+ sz = (vaddr_t)e->e_esigcode - (vaddr_t)e->e_sigcode;
+
+ /*
+ * 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.
+ */
+ if (e->e_sigobject == NULL) {
+ vaddr_t va;
+ int r;
+
+ e->e_sigobject = uao_create(sz, 0);
+ uao_reference(e->e_sigobject); /* permanent reference */
+
+ va = vm_map_min(kernel_map); /* hint */
+ if ((r = uvm_map(kernel_map, &va, round_page(sz), e->e_sigobject,
+ 0, 0, UVM_MAPFLAG(UVM_PROT_RW, UVM_PROT_RW,
+ UVM_INH_SHARE, UVM_ADV_RANDOM, 0)))) {
+ printf("kernel mapping failed %d\n", r);
+ return (ENOMEM);
+ }
+ memcpy((void *)va, e->e_sigcode, sz);
+ uvm_unmap(kernel_map, va, va + round_page(sz));
+ }
+
+ /* Just a hint to uvm_mmap where to put it. */
+ p->p_sigcode = round_page((vaddr_t)p->p_vmspace->vm_daddr + MAXDSIZ);
+ uao_reference(e->e_sigobject);
+ if (uvm_map(&p->p_vmspace->vm_map, &p->p_sigcode, round_page(sz),
+ e->e_sigobject, 0, 0, UVM_MAPFLAG(UVM_PROT_RX, UVM_PROT_RX,
+ UVM_INH_SHARE, UVM_ADV_RANDOM, 0))) {
+ printf("user mapping failed\n");
+ return (ENOMEM);
+ }
+
+ return (0);
+}