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.c58
1 files changed, 46 insertions, 12 deletions
diff --git a/sys/kern/kern_exec.c b/sys/kern/kern_exec.c
index 77e7bc5..47b3a33 100644
--- a/sys/kern/kern_exec.c
+++ b/sys/kern/kern_exec.c
@@ -80,6 +80,8 @@ static int sysctl_kern_usrstack(SYSCTL_HANDLER_ARGS);
static int sysctl_kern_stackprot(SYSCTL_HANDLER_ARGS);
static int kern_execve(struct thread *td, char *fname, char **argv,
char **envv, struct mac *mac_p);
+static int do_execve(struct thread *td, char *fname, char **argv,
+ char **envv, struct mac *mac_p);
/* XXX This should be vm_size_t. */
SYSCTL_PROC(_kern, KERN_PS_STRINGS, ps_strings, CTLTYPE_ULONG|CTLFLAG_RD,
@@ -205,6 +207,44 @@ __mac_execve(td, uap)
#endif
}
+static int
+kern_execve(td, fname, argv, envv, mac_p)
+ struct thread *td;
+ char *fname;
+ char **argv;
+ char **envv;
+ struct mac *mac_p;
+{
+ struct proc *p = td->td_proc;
+ int error;
+
+ if (p->p_flag & P_HADTHREADS) {
+ PROC_LOCK(p);
+ if (thread_single(SINGLE_BOUNDARY)) {
+ PROC_UNLOCK(p);
+ return (ERESTART); /* Try again later. */
+ }
+ PROC_UNLOCK(p);
+ }
+
+ error = do_execve(td, fname, argv, envv, mac_p);
+
+ if (p->p_flag & P_HADTHREADS) {
+ PROC_LOCK(p);
+ /*
+ * If success, we upgrade to SINGLE_EXIT state to
+ * force other threads to suicide.
+ */
+ if (error == 0)
+ thread_single(SINGLE_EXIT);
+ else
+ thread_single_end();
+ PROC_UNLOCK(p);
+ }
+
+ return (error);
+}
+
/*
* In-kernel implementation of execve(). All arguments are assumed to be
* userspace pointers from the passed thread.
@@ -212,7 +252,7 @@ __mac_execve(td, uap)
* MPSAFE
*/
static int
-kern_execve(td, fname, argv, envv, mac_p)
+do_execve(td, fname, argv, envv, mac_p)
struct thread *td;
char *fname;
char **argv;
@@ -254,16 +294,6 @@ kern_execve(td, fname, argv, envv, mac_p)
PROC_LOCK(p);
KASSERT((p->p_flag & P_INEXEC) == 0,
("%s(): process already has P_INEXEC flag", __func__));
- if (p->p_flag & P_HADTHREADS) {
- if (thread_single(SINGLE_EXIT)) {
- PROC_UNLOCK(p);
- return (ERESTART); /* Try again later. */
- }
- /*
- * If we get here all other threads are dead,
- * and threading mode has been turned off
- */
- }
p->p_flag |= P_INEXEC;
PROC_UNLOCK(p);
@@ -624,9 +654,13 @@ interpret:
/*
* If tracing the process, trap to debugger so breakpoints
* can be set before the program executes.
+ * Use tdsignal to deliver signal to current thread, use
+ * psignal may cause the signal to be delivered to wrong thread
+ * because that thread will exit, remember we are going to enter
+ * single thread mode.
*/
if (p->p_flag & P_TRACED)
- psignal(p, SIGTRAP);
+ tdsignal(td, SIGTRAP, SIGTARGET_TD);
/* clear "fork but no exec" flag, as we _are_ execing */
p->p_acflag &= ~AFORK;
OpenPOWER on IntegriCloud