diff options
Diffstat (limited to 'usr/src/lib/libc/port/threads')
-rw-r--r-- | usr/src/lib/libc/port/threads/sigaction.c | 74 | ||||
-rw-r--r-- | usr/src/lib/libc/port/threads/thr.c | 13 |
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); |