summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoremaste <emaste@FreeBSD.org>2018-12-19 17:52:56 +0000
committeremaste <emaste@FreeBSD.org>2018-12-19 17:52:56 +0000
commite72e16e70c2180817d0ae932b15c52c18a30d107 (patch)
tree611af7247f66a8f2032ce32136e372e5dba75127
parent888fdfbae1e6345c054a031e3d996b1f3a19149b (diff)
downloadFreeBSD-src-e72e16e70c2180817d0ae932b15c52c18a30d107.zip
FreeBSD-src-e72e16e70c2180817d0ae932b15c52c18a30d107.tar.gz
MFS11 r340290: Only clear a pending thread event if one is pending.
This fixes a panic when attaching to an already-stopped process. Also do some other clean ups for control flow of sendsig section. Submitted by: markj Approved by: so Security: FreeBSD-EN-18:16.ptrace Sponsored by: The FreeBSD Foundation
-rw-r--r--sys/kern/sys_process.c102
1 files changed, 53 insertions, 49 deletions
diff --git a/sys/kern/sys_process.c b/sys/kern/sys_process.c
index 67aaff6..9e6e1aa 100644
--- a/sys/kern/sys_process.c
+++ b/sys/kern/sys_process.c
@@ -869,19 +869,13 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data)
}
/* not currently stopped */
- if ((p->p_flag & (P_STOPPED_SIG | P_STOPPED_TRACE)) == 0 ||
+ if ((p->p_flag & P_STOPPED_TRACE) == 0 ||
p->p_suspcount != p->p_numthreads ||
(p->p_flag & P_WAITED) == 0) {
error = EBUSY;
goto fail;
}
- if ((p->p_flag & P_STOPPED_TRACE) == 0) {
- static int count = 0;
- if (count++ == 0)
- printf("P_STOPPED_TRACE not set.\n");
- }
-
/* OK */
break;
}
@@ -926,10 +920,27 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data)
if (p->p_pptr != td->td_proc) {
proc_reparent(p, td->td_proc);
}
- data = SIGSTOP;
CTR2(KTR_PTRACE, "PT_ATTACH: pid %d, oppid %d", p->p_pid,
p->p_oppid);
- goto sendsig; /* in PT_CONTINUE below */
+
+ sx_xunlock(&proctree_lock);
+ proctree_locked = 0;
+ MPASS(p->p_xthread == NULL);
+ MPASS((p->p_flag & P_STOPPED_TRACE) == 0);
+
+ /*
+ * If already stopped due to a stop signal, clear the
+ * existing stop before triggering a traced SIGSTOP.
+ */
+ if ((p->p_flag & P_STOPPED_SIG) != 0) {
+ PROC_SLOCK(p);
+ p->p_flag &= ~(P_STOPPED_SIG | P_WAITED);
+ thread_unsuspend(p);
+ PROC_SUNLOCK(p);
+ }
+
+ kern_psignal(p, SIGSTOP);
+ break;
case PT_CLEARSTEP:
CTR2(KTR_PTRACE, "PT_CLEARSTEP: tid %d (pid %d)", td2->td_tid,
@@ -1117,8 +1128,10 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data)
sigqueue_delete(&td3->td_sigqueue,
SIGSTOP);
}
- td3->td_dbgflags &= ~(TDB_XSIG | TDB_FSTP);
+ td3->td_dbgflags &= ~(TDB_XSIG | TDB_FSTP |
+ TDB_SUSPEND);
}
+
if ((p->p_flag2 & P2_PTRACE_FSTP) != 0) {
sigqueue_delete(&p->p_sigqueue, SIGSTOP);
p->p_flag2 &= ~P2_PTRACE_FSTP;
@@ -1129,54 +1142,45 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data)
break;
}
+ sx_xunlock(&proctree_lock);
+ proctree_locked = 0;
+
sendsig:
- /*
+ MPASS(proctree_locked == 0);
+
+ /*
* Clear the pending event for the thread that just
* reported its event (p_xthread). This may not be
* the thread passed to PT_CONTINUE, PT_STEP, etc. if
* the debugger is resuming a different thread.
+ *
+ * Deliver any pending signal via the reporting thread.
*/
- td2 = p->p_xthread;
- if (proctree_locked) {
- sx_xunlock(&proctree_lock);
- proctree_locked = 0;
- }
- p->p_xsig = data;
+ MPASS(p->p_xthread != NULL);
+ p->p_xthread->td_dbgflags &= ~TDB_XSIG;
+ p->p_xthread->td_xsig = data;
p->p_xthread = NULL;
- if ((p->p_flag & (P_STOPPED_SIG | P_STOPPED_TRACE)) != 0) {
- /* deliver or queue signal */
- td2->td_dbgflags &= ~TDB_XSIG;
- td2->td_xsig = data;
+ p->p_xsig = data;
- /*
- * P_WKILLED is insurance that a PT_KILL/SIGKILL always
- * works immediately, even if another thread is
- * unsuspended first and attempts to handle a different
- * signal or if the POSIX.1b style signal queue cannot
- * accommodate any new signals.
- */
- if (data == SIGKILL)
- p->p_flag |= P_WKILLED;
+ /*
+ * P_WKILLED is insurance that a PT_KILL/SIGKILL
+ * always works immediately, even if another thread is
+ * unsuspended first and attempts to handle a
+ * different signal or if the POSIX.1b style signal
+ * queue cannot accommodate any new signals.
+ */
+ if (data == SIGKILL)
+ p->p_flag |= P_WKILLED;
- if (req == PT_DETACH) {
- FOREACH_THREAD_IN_PROC(p, td3)
- td3->td_dbgflags &= ~TDB_SUSPEND;
- }
- /*
- * unsuspend all threads, to not let a thread run,
- * you should use PT_SUSPEND to suspend it before
- * continuing process.
- */
- PROC_SLOCK(p);
- p->p_flag &= ~(P_STOPPED_TRACE|P_STOPPED_SIG|P_WAITED);
- thread_unsuspend(p);
- PROC_SUNLOCK(p);
- if (req == PT_ATTACH)
- kern_psignal(p, data);
- } else {
- if (data)
- kern_psignal(p, data);
- }
+ /*
+ * Unsuspend all threads. To leave a thread
+ * suspended, use PT_SUSPEND to suspend it before
+ * continuing the process.
+ */
+ PROC_SLOCK(p);
+ p->p_flag &= ~(P_STOPPED_TRACE | P_STOPPED_SIG | P_WAITED);
+ thread_unsuspend(p);
+ PROC_SUNLOCK(p);
break;
case PT_WRITE_I:
OpenPOWER on IntegriCloud