summaryrefslogtreecommitdiffstats
path: root/sys/kern/kern_exec.c
diff options
context:
space:
mode:
authordavidxu <davidxu@FreeBSD.org>2004-10-06 00:40:41 +0000
committerdavidxu <davidxu@FreeBSD.org>2004-10-06 00:40:41 +0000
commit793ea9317eb55a19242d9f6648f3a2f128b8934c (patch)
tree432efd811bd18d95f48da3533a80d28fea1512ec /sys/kern/kern_exec.c
parentc2f56cb723c50c2fdc1fdc81aa886ca10d05c837 (diff)
downloadFreeBSD-src-793ea9317eb55a19242d9f6648f3a2f128b8934c.zip
FreeBSD-src-793ea9317eb55a19242d9f6648f3a2f128b8934c.tar.gz
In original kern_execve() code, at the start of the function, it forces
all other threads to suicide, problem is execve() could be failed, and a failed execve() would change threaded process to unthreaded, this side effect is unexpected. The new code introduces a new single threading mode SINGLE_BOUNDARY, in the mode, all threads should suspend themself at user boundary except the singler. we can not use SINGLE_NO_EXIT because we want to start from a clean state if execve() is successful, suspending other threads at unknown point and later resuming them from there and forcing them to exit at user boundary may cause the process to start from a dirty state. If execve() is successful, current thread upgrades to SINGLE_EXIT mode and forces other threads to suicide at user boundary, otherwise, other threads will be resumed and their interrupted syscall will be restarted. Reviewed by: julian
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