summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrick Mooney <pmooney@pfmooney.com>2016-12-05 23:14:19 +0000
committerJason King <jason.king@joyent.com>2020-04-08 19:41:51 -0500
commit72a6dc127431d372b6b6136087c736300544f8b7 (patch)
treede4356a799418ec5bcae77b1f7c11971e4f367ac
parenta47ab03e261661b7326ab0b642649034886be632 (diff)
downloadillumos-joyent-72a6dc127431d372b6b6136087c736300544f8b7.tar.gz
7637 restorecontext(ucontext_t *ucp) leaves all maskable signals blocked in curthread->t_hold
Reviewed by: Robert Mustacchi <rm@joyent.com> Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com> Reviewed by: Toomas Soome <tsoome@me.com> Approved by: Dan McDonald <danmcd@joyent.com>
-rw-r--r--usr/src/uts/common/fs/proc/prdata.h1
-rw-r--r--usr/src/uts/common/fs/proc/prioctl.c22
-rw-r--r--usr/src/uts/common/fs/proc/prsubr.c32
-rw-r--r--usr/src/uts/common/os/schedctl.c18
4 files changed, 45 insertions, 28 deletions
diff --git a/usr/src/uts/common/fs/proc/prdata.h b/usr/src/uts/common/fs/proc/prdata.h
index b010d6a37e..59315368d7 100644
--- a/usr/src/uts/common/fs/proc/prdata.h
+++ b/usr/src/uts/common/fs/proc/prdata.h
@@ -381,6 +381,7 @@ extern int clear_watched_area(proc_t *, struct watched_area *);
extern void pr_free_watchpoints(proc_t *);
extern proc_t *pr_cancel_watch(prnode_t *);
extern struct seg *break_seg(proc_t *);
+extern void prgethold(kthread_t *, sigset_t *);
/*
* Machine-dependent routines (defined in prmachdep.c).
diff --git a/usr/src/uts/common/fs/proc/prioctl.c b/usr/src/uts/common/fs/proc/prioctl.c
index 8202e49df0..630ab0b2e3 100644
--- a/usr/src/uts/common/fs/proc/prioctl.c
+++ b/usr/src/uts/common/fs/proc/prioctl.c
@@ -930,8 +930,7 @@ startover:
}
case PIOCGHOLD: /* get signal-hold mask */
- schedctl_finish_sigblock(t);
- sigktou(&t->t_hold, &un.holdmask);
+ prgethold(t, &un.holdmask);
prunlock(pnp);
if (copyout(&un.holdmask, cmaddr, sizeof (un.holdmask)))
error = EFAULT;
@@ -1395,8 +1394,7 @@ oprgetstatus32(kthread_t *t, prstatus32_t *sp, zone_t *zp)
sp->pr_cursig = lwp->lwp_cursig;
prassignset(&sp->pr_sigpend, &p->p_sig);
prassignset(&sp->pr_lwppend, &t->t_sig);
- schedctl_finish_sigblock(t);
- prassignset(&sp->pr_sighold, &t->t_hold);
+ prgethold(t, &sp->pr_sighold);
sp->pr_altstack.ss_sp =
(caddr32_t)(uintptr_t)lwp->lwp_sigaltstack.ss_sp;
sp->pr_altstack.ss_size = (size32_t)lwp->lwp_sigaltstack.ss_size;
@@ -1673,14 +1671,8 @@ oprgetpsinfo32(proc_t *p, prpsinfo32_t *psp, kthread_t *tp)
/*ARGSUSED*/
static int
-prioctl32(
- struct vnode *vp,
- int cmd,
- intptr_t arg,
- int flag,
- cred_t *cr,
- int *rvalp,
- caller_context_t *ct)
+prioctl32(struct vnode *vp, int cmd, intptr_t arg, int flag, cred_t *cr,
+ int *rvalp, caller_context_t *ct)
{
int nsig = PROC_IS_BRANDED(curproc)? BROP(curproc)->b_nsig : NSIG;
caddr_t cmaddr = (caddr_t)arg;
@@ -2557,8 +2549,7 @@ startover:
}
case PIOCGHOLD: /* get signal-hold mask */
- schedctl_finish_sigblock(t);
- sigktou(&t->t_hold, &un32.holdmask);
+ prgethold(t, &un32.holdmask);
prunlock(pnp);
if (copyout(&un32.holdmask, cmaddr, sizeof (un32.holdmask)))
error = EFAULT;
@@ -3235,8 +3226,7 @@ oprgetstatus(kthread_t *t, prstatus_t *sp, zone_t *zp)
sp->pr_cursig = lwp->lwp_cursig;
prassignset(&sp->pr_sigpend, &p->p_sig);
prassignset(&sp->pr_lwppend, &t->t_sig);
- schedctl_finish_sigblock(t);
- prassignset(&sp->pr_sighold, &t->t_hold);
+ prgethold(t, &sp->pr_sighold);
sp->pr_altstack = lwp->lwp_sigaltstack;
prgetaction(p, up, lwp->lwp_cursig, &sp->pr_action);
sp->pr_pid = p->p_pid;
diff --git a/usr/src/uts/common/fs/proc/prsubr.c b/usr/src/uts/common/fs/proc/prsubr.c
index 26e33330fb..8cda5f57b3 100644
--- a/usr/src/uts/common/fs/proc/prsubr.c
+++ b/usr/src/uts/common/fs/proc/prsubr.c
@@ -931,6 +931,29 @@ prgetstatus(proc_t *p, pstatus_t *sp, zone_t *zp)
sp->pr_flags = sp->pr_lwp.pr_flags;
}
+/*
+ * Query mask of held signals for a given thread.
+ *
+ * This makes use of schedctl_sigblock() to query if userspace has requested
+ * that all maskable signals be held. While it would be tempting to call
+ * schedctl_finish_sigblock() and apply that update to t->t_hold, it cannot be
+ * done safely without the risk of racing with the thread under consideration.
+ */
+void
+prgethold(kthread_t *t, sigset_t *sp)
+{
+ k_sigset_t set;
+
+ if (schedctl_sigblock(t)) {
+ set.__sigbits[0] = FILLSET0 & ~CANTMASK0;
+ set.__sigbits[1] = FILLSET1 & ~CANTMASK1;
+ set.__sigbits[2] = FILLSET2 & ~CANTMASK2;
+ } else {
+ set = t->t_hold;
+ }
+ sigktou(&set, sp);
+}
+
#ifdef _SYSCALL32_IMPL
void
prgetlwpstatus32(kthread_t *t, lwpstatus32_t *sp, zone_t *zp)
@@ -992,8 +1015,7 @@ prgetlwpstatus32(kthread_t *t, lwpstatus32_t *sp, zone_t *zp)
sp->pr_lwpid = t->t_tid;
sp->pr_cursig = lwp->lwp_cursig;
prassignset(&sp->pr_lwppend, &t->t_sig);
- schedctl_finish_sigblock(t);
- prassignset(&sp->pr_lwphold, &t->t_hold);
+ prgethold(t, &sp->pr_lwphold);
if (t->t_whystop == PR_FAULTED) {
siginfo_kto32(&lwp->lwp_siginfo, &sp->pr_info);
if (t->t_whatstop == FLTPAGE)
@@ -1224,8 +1246,7 @@ prgetlwpstatus(kthread_t *t, lwpstatus_t *sp, zone_t *zp)
sp->pr_lwpid = t->t_tid;
sp->pr_cursig = lwp->lwp_cursig;
prassignset(&sp->pr_lwppend, &t->t_sig);
- schedctl_finish_sigblock(t);
- prassignset(&sp->pr_lwphold, &t->t_hold);
+ prgethold(t, &sp->pr_lwphold);
if (t->t_whystop == PR_FAULTED)
bcopy(&lwp->lwp_siginfo,
&sp->pr_info, sizeof (k_siginfo_t));
@@ -3197,7 +3218,6 @@ prgetlwpsinfo(kthread_t *t, lwpsinfo_t *psp)
void
prgetlwpsinfo32(kthread_t *t, lwpsinfo32_t *psp)
{
- proc_t *p = ttoproc(t);
klwp_t *lwp = ttolwp(t);
sobj_ops_t *sobj;
char c, state;
@@ -3205,7 +3225,7 @@ prgetlwpsinfo32(kthread_t *t, lwpsinfo32_t *psp)
int retval, niceval;
hrtime_t hrutime, hrstime;
- ASSERT(MUTEX_HELD(&p->p_lock));
+ ASSERT(MUTEX_HELD(&ttoproc(t)->p_lock));
bzero(psp, sizeof (*psp));
diff --git a/usr/src/uts/common/os/schedctl.c b/usr/src/uts/common/os/schedctl.c
index 5721083751..18b396a765 100644
--- a/usr/src/uts/common/os/schedctl.c
+++ b/usr/src/uts/common/os/schedctl.c
@@ -22,6 +22,7 @@
/*
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ * Copyright 2016 Joyent, Inc.
*/
#include <sys/types.h>
@@ -327,12 +328,17 @@ schedctl_sigblock(kthread_t *t)
/*
- * If the sc_sigblock field is set for the specified thread, set
- * its signal mask to block all maskable signals, then clear the
- * sc_sigblock field. This finishes what user-level code requested
- * to be done when it set tdp->sc_shared->sc_sigblock non-zero.
- * Called from signal-related code either by the current thread for
- * itself or by a thread that holds the process's p_lock (/proc code).
+ * If the sc_sigblock field is set for the specified thread, set its signal
+ * mask to block all maskable signals, then clear the sc_sigblock field. This
+ * accomplishes what user-level code requested to be done when it set
+ * tdp->sc_shared->sc_sigblock non-zero.
+ *
+ * This is generally called by signal-related code in the current thread. In
+ * order to call against a thread other than curthread, p_lock for the
+ * containing process must be held. Even then, the caller is not protected
+ * from races with the thread in question updating its own fields. It is the
+ * responsibility of the caller to perform additional synchronization.
+ *
*/
void
schedctl_finish_sigblock(kthread_t *t)