summaryrefslogtreecommitdiff
path: root/usr/src/lib/libc/port/threads
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/lib/libc/port/threads')
-rw-r--r--usr/src/lib/libc/port/threads/sigaction.c74
-rw-r--r--usr/src/lib/libc/port/threads/thr.c13
2 files changed, 67 insertions, 20 deletions
diff --git a/usr/src/lib/libc/port/threads/sigaction.c b/usr/src/lib/libc/port/threads/sigaction.c
index 1417c1e18a..8c48989a17 100644
--- a/usr/src/lib/libc/port/threads/sigaction.c
+++ b/usr/src/lib/libc/port/threads/sigaction.c
@@ -22,6 +22,7 @@
/*
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ * Copyright 2015 Joyent, Inc.
*/
/*
@@ -288,6 +289,24 @@ take_deferred_signal(int sig)
thr_panic("take_deferred_signal(): __sigresend() failed");
}
+/*
+ * sigacthandler() attempts to clean up dangling uc_link pointers in
+ * signal handling contexts when libc believes us to have escaped
+ * a signal handler incorrectly in the past.
+ *
+ * Branded processes have a legitimate use for a chain including contexts
+ * other than those used for signal handling when tracking emulation
+ * requests from the kernel. We allow them to disable this cleanup
+ * behaviour.
+ */
+static int escaped_context_cleanup = 1;
+
+void
+set_escaped_context_cleanup(int on)
+{
+ escaped_context_cleanup = on;
+}
+
void
sigacthandler(int sig, siginfo_t *sip, void *uvp)
{
@@ -310,7 +329,7 @@ sigacthandler(int sig, siginfo_t *sip, void *uvp)
* we are actually executing at main level (self->ul_siglink == NULL).
* See the code for setjmp()/longjmp() for more details.
*/
- if (self->ul_siglink == NULL)
+ if (escaped_context_cleanup && self->ul_siglink == NULL)
ucp->uc_link = NULL;
/*
@@ -462,11 +481,12 @@ sigaction(int sig, const struct sigaction *nact, struct sigaction *oact)
}
/*
- * This is a private interface for the linux brand interface.
+ * This is a private interface for the lx brand.
*/
void
setsigacthandler(void (*nsigacthandler)(int, siginfo_t *, void *),
- void (**osigacthandler)(int, siginfo_t *, void *))
+ void (**osigacthandler)(int, siginfo_t *, void *),
+ int (*brsetctxt)(const ucontext_t *))
{
ulwp_t *self = curthread;
uberdata_t *udp = self->ul_uberdata;
@@ -475,6 +495,9 @@ setsigacthandler(void (*nsigacthandler)(int, siginfo_t *, void *),
*osigacthandler = udp->sigacthandler;
udp->sigacthandler = nsigacthandler;
+
+ if (brsetctxt != NULL)
+ udp->setctxt = brsetctxt;
}
/*
@@ -521,11 +544,39 @@ set_setcontext_enforcement(int on)
setcontext_enforcement = on;
}
+/*
+ * The LX brand emulation library implements an operation that is analogous to
+ * setcontext(), but takes a different path in to the kernel. So that it can
+ * correctly restore a signal mask, we expose just the signal mask handling
+ * part of the regular setcontext() routine as a private interface.
+ */
+void
+setcontext_sigmask(ucontext_t *ucp)
+{
+ ulwp_t *self = curthread;
+
+ if (ucp->uc_flags & UC_SIGMASK) {
+ block_all_signals(self);
+ delete_reserved_signals(&ucp->uc_sigmask);
+ self->ul_sigmask = ucp->uc_sigmask;
+ if (self->ul_cursig) {
+ /*
+ * We have a deferred signal present.
+ * The signal mask will be set when the
+ * signal is taken in take_deferred_signal().
+ */
+ ASSERT(self->ul_critical + self->ul_sigdefer != 0);
+ ucp->uc_flags &= ~UC_SIGMASK;
+ }
+ }
+}
+
#pragma weak _setcontext = setcontext
int
setcontext(const ucontext_t *ucp)
{
ulwp_t *self = curthread;
+ uberdata_t *udp = self->ul_uberdata;
int ret;
ucontext_t uc;
@@ -540,20 +591,7 @@ setcontext(const ucontext_t *ucp)
/*
* Restore previous signal mask and context link.
*/
- if (uc.uc_flags & UC_SIGMASK) {
- block_all_signals(self);
- delete_reserved_signals(&uc.uc_sigmask);
- self->ul_sigmask = uc.uc_sigmask;
- if (self->ul_cursig) {
- /*
- * We have a deferred signal present.
- * The signal mask will be set when the
- * signal is taken in take_deferred_signal().
- */
- ASSERT(self->ul_critical + self->ul_sigdefer != 0);
- uc.uc_flags &= ~UC_SIGMASK;
- }
- }
+ setcontext_sigmask(&uc);
self->ul_siglink = uc.uc_link;
/*
@@ -588,7 +626,7 @@ setcontext(const ucontext_t *ucp)
*/
set_parking_flag(self, 0);
self->ul_sp = 0;
- ret = __setcontext(&uc);
+ ret = udp->setctxt(&uc);
/*
* It is OK for setcontext() to return if the user has not specified
diff --git a/usr/src/lib/libc/port/threads/thr.c b/usr/src/lib/libc/port/threads/thr.c
index 0ee28c0c59..d8bf7799f4 100644
--- a/usr/src/lib/libc/port/threads/thr.c
+++ b/usr/src/lib/libc/port/threads/thr.c
@@ -127,6 +127,7 @@ uberdata_t __uberdata = {
0, /* ndaemons */
0, /* pid */
sigacthandler, /* sigacthandler */
+ __setcontext, /* setctxt */
NULL, /* lwp_stacks */
NULL, /* lwp_laststack */
0, /* nfreestack */
@@ -139,6 +140,7 @@ uberdata_t __uberdata = {
NULL, /* robustlocks */
NULL, /* robustlist */
NULL, /* progname */
+ NULL, /* ub_broot */
NULL, /* ub_comm_page */
NULL, /* __tdb_bootstrap */
{ /* tdb */
@@ -1232,13 +1234,19 @@ init_auxv_data(uberdata_t *udp)
{
Dl_argsinfo_t args;
+ udp->ub_broot = NULL;
udp->ub_comm_page = NULL;
if (dlinfo(RTLD_SELF, RTLD_DI_ARGSINFO, &args) < 0)
return;
while (args.dla_auxv->a_type != AT_NULL) {
- if (args.dla_auxv->a_type == AT_SUN_COMMPAGE) {
+ switch (args.dla_auxv->a_type) {
+ case AT_SUN_BRAND_NROOT:
+ udp->ub_broot = args.dla_auxv->a_un.a_ptr;
+ break;
+ case AT_SUN_COMMPAGE:
udp->ub_comm_page = args.dla_auxv->a_un.a_ptr;
+ break;
}
args.dla_auxv++;
}
@@ -1282,7 +1290,8 @@ libc_init(void)
/*
* Every libc, regardless of link map, needs to go through and check
* its aux vectors. Doing so will indicate whether or not this has
- * been given a comm page (to optimize certain system actions).
+ * been given a brand root (used to qualify various other data) or a
+ * comm page (to optimize certain system actions).
*/
init_auxv_data(udp);