From ab74c8433303a6d45f5efca5a14e0bb9d91f62ae Mon Sep 17 00:00:00 2001 From: Konstantin Belousov Date: Wed, 29 May 2019 14:05:27 +0000 Subject: [PATCH] Do not go into sleep in sleepq_catch_signals() when SIGSTOP from PT_ATTACH was consumed. In particular, do not clear TDP_FSTP in ptracestop() if td_wchan is non-NULL. Leave it to sleepq_catch_signal() to clear and convert zero return code to EINTR. Otherwise, per submitter report, if the PT_ATTACH SIGSTOP was delivered right after the thread was added to the sleepqueue but not yet really sleep, and cursig() caused debugger attach, the thread sleeps instead of returning to the userspace boundary with EINTR. PR: 231445 Reported by: Efi Weiss Reviewed by: markj Sponsored by: The FreeBSD Foundation MFC after: 2 weeks Differential revision: https://reviews.freebsd.org/D20381 --- sys/kern/kern_sig.c | 10 +++++++++- sys/kern/subr_sleepqueue.c | 13 +++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c index 6e7339017fc3..8dbcb87698bc 100644 --- a/sys/kern/kern_sig.c +++ b/sys/kern/kern_sig.c @@ -2576,7 +2576,15 @@ ptracestop(struct thread *td, int sig, ksiginfo_t *si) p->p_xthread == NULL)) { p->p_xsig = sig; p->p_xthread = td; - td->td_dbgflags &= ~TDB_FSTP; + + /* + * If we are on sleepqueue already, + * let sleepqueue code decide if it + * needs to go sleep after attach. + */ + if (td->td_wchan == NULL) + td->td_dbgflags &= ~TDB_FSTP; + p->p_flag2 &= ~P2_PTRACE_FSTP; p->p_flag |= P_STOPPED_SIG | P_STOPPED_TRACE; sig_suspend_threads(td, p, 0); diff --git a/sys/kern/subr_sleepqueue.c b/sys/kern/subr_sleepqueue.c index 6f256167100a..7f8a66eb8f5b 100644 --- a/sys/kern/subr_sleepqueue.c +++ b/sys/kern/subr_sleepqueue.c @@ -498,6 +498,19 @@ sleepq_catch_signals(void *wchan, int pri) } else { mtx_unlock(&ps->ps_mtx); } + + /* + * Do not go into sleep if this thread was the + * ptrace(2) attach leader. cursig() consumed + * SIGSTOP from PT_ATTACH, but we usually act + * on the signal by interrupting sleep, and + * should do that here as well. + */ + if ((td->td_dbgflags & TDB_FSTP) != 0) { + if (ret == 0) + ret = EINTR; + td->td_dbgflags &= ~TDB_FSTP; + } } /* * Lock the per-process spinlock prior to dropping the PROC_LOCK