summaryrefslogtreecommitdiffstats
path: root/sys/kern/kern_exec.c
diff options
context:
space:
mode:
authorart <art@openbsd.org>2002-07-20 19:24:55 +0000
committerart <art@openbsd.org>2002-07-20 19:24:55 +0000
commit4a5480fe18b84efa6a06b21bf545eb9124282da7 (patch)
tree1ae6886fef3407c1df68824801d7de5f46ff2d31 /sys/kern/kern_exec.c
parentproperly split yacc and lex use (diff)
downloadwireguard-openbsd-4a5480fe18b84efa6a06b21bf545eb9124282da7.tar.xz
wireguard-openbsd-4a5480fe18b84efa6a06b21bf545eb9124282da7.zip
Instead of copying out the signal trampoline on top of the stack, create
an uvm aobj, copy out the signal trampoline into it and share that page among all processes for the same emulation. This also requires us to actually be able to tell signal code where the trampoline is located, so introduce a new field in struct proc - p_sigcode that is a pointer to sigcode. This allows us to remove all the ugly calculations of the signal trampoline address done in every sendsig function in the tree (that's why so many files are changed). Tested by various people. ok deraadt@
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);
+}