summaryrefslogtreecommitdiff
path: root/sys/kern/kern_sig.c
diff options
context:
space:
mode:
authorClaudio Jeker <claudio@cvs.openbsd.org>2022-03-11 10:05:39 +0000
committerClaudio Jeker <claudio@cvs.openbsd.org>2022-03-11 10:05:39 +0000
commit149d1412c6d851f9544333aa9734149234c0b059 (patch)
tree545c66393c320bc73961fc65a380c9eadafc35b7 /sys/kern/kern_sig.c
parent0b4630ac1be88ce5003214be70d70a8299a76c8b (diff)
Revert part of rev 1.293. Using cursig() to deliver masked signals
to the debugger can cause a loop between the debugger and cursig() if the signal is masked. cursig() has no way to know which signal was already delivered to the debugger and so it delivers the same signal over and over again. Instead handle traps to masked signals directly in trapsignal. This is what rev 1.293 was mostly about. If SIGTRAP was masked by the process breakpoints no longer worked since the signal deliver to the debugger did not happen. Doing this case in trapsignal solves both the problem with the loop and the delivery of masked traps. Problem reported and fix tested by matthieu@ OK kettenis@ mpi@
Diffstat (limited to 'sys/kern/kern_sig.c')
-rw-r--r--sys/kern/kern_sig.c43
1 files changed, 38 insertions, 5 deletions
diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c
index 9109b65847b..f9bd8b74e1b 100644
--- a/sys/kern/kern_sig.c
+++ b/sys/kern/kern_sig.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kern_sig.c,v 1.294 2022/02/14 11:26:05 claudio Exp $ */
+/* $OpenBSD: kern_sig.c,v 1.295 2022/03/11 10:05:38 claudio Exp $ */
/* $NetBSD: kern_sig.c,v 1.54 1996/04/22 01:38:32 christos Exp $ */
/*
@@ -846,6 +846,41 @@ trapsignal(struct proc *p, int signum, u_long trapno, int code,
p->p_sigval = sigval;
/*
+ * If traced, stop if signal is masked, and stay stopped
+ * until released by the debugger. If our parent process
+ * is waiting for us, don't hang as we could deadlock.
+ */
+ if (((pr->ps_flags & (PS_TRACED | PS_PPWAIT)) == PS_TRACED) &&
+ signum != SIGKILL && (p->p_sigmask & mask) != 0) {
+ int s;
+
+ pr->ps_xsig = signum;
+
+ single_thread_set(p, SINGLE_SUSPEND, 0);
+
+ SCHED_LOCK(s);
+ proc_stop(p, 1);
+ SCHED_UNLOCK(s);
+
+ single_thread_clear(p, 0);
+
+ /*
+ * If we are no longer being traced, or the parent
+ * didn't give us a signal, skip sending the signal.
+ */
+ if ((pr->ps_flags & PS_TRACED) == 0 ||
+ pr->ps_xsig == 0) {
+ KERNEL_UNLOCK();
+ return;
+ }
+
+ /* update signal info */
+ signum = pr->ps_xsig;
+ p->p_sisig = signum;
+ mask = sigmask(signum);
+ }
+
+ /*
* Signals like SIGBUS and SIGSEGV should not, when
* generated by the kernel, be ignorable or blockable.
* If it is and we're not being traced, then just kill
@@ -1217,9 +1252,7 @@ cursig(struct proc *p, struct sigctx *sctx)
KASSERT(p == curproc);
for (;;) {
- mask = (p->p_siglist | pr->ps_siglist);
- if (!ISSET(pr->ps_flags, PS_TRACED))
- mask &= ~p->p_sigmask;
+ mask = SIGPENDING(p);
if (pr->ps_flags & PS_PPWAIT)
mask &= ~STOPSIGMASK;
if (mask == 0) /* no signal to send */
@@ -1924,7 +1957,7 @@ userret(struct proc *p)
KERNEL_UNLOCK();
}
- if (SIGPENDING(p) != 0 || ISSET(p->p_p->ps_flags, PS_TRACED)) {
+ if (SIGPENDING(p) != 0) {
KERNEL_LOCK();
while ((signum = cursig(p, &ctx)) != 0)
postsig(p, signum, &ctx);