summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBryan Cantrill <bryan@joyent.com>2018-10-02 00:08:12 +0000
committerBryan Cantrill <bryan@joyent.com>2018-10-02 21:48:52 +0000
commitfe10e0740dd87c89538183dcb46f8787d84d1c54 (patch)
treebd75c919cba65bdc0559b12c65f8655ac33d68fa
parent1f6101e0488d5d4aff07f6da56980c87fc92e790 (diff)
downloadillumos-joyent-fe10e0740dd87c89538183dcb46f8787d84d1c54.tar.gz
OS-7121 lx vfork and signal handling still racey
Reviewed by: Patrick Mooney <patrick.mooney@joyent.com> Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com> Reviewed by: Ryan Zezeski <rpz@joyent.com> Approved by: Robert Mustacchi <rm@joyent.com>
-rw-r--r--usr/src/lib/brand/lx/lx_brand/common/signal.c33
-rw-r--r--usr/src/lib/brand/lx/lx_brand/sys/lx_misc.h3
-rw-r--r--usr/src/uts/common/brand/lx/os/lx_brand.c12
-rw-r--r--usr/src/uts/common/brand/lx/sys/lx_brand.h2
4 files changed, 44 insertions, 6 deletions
diff --git a/usr/src/lib/brand/lx/lx_brand/common/signal.c b/usr/src/lib/brand/lx/lx_brand/common/signal.c
index a8e3601cb9..b9356d16ab 100644
--- a/usr/src/lib/brand/lx/lx_brand/common/signal.c
+++ b/usr/src/lib/brand/lx/lx_brand/common/signal.c
@@ -1450,7 +1450,7 @@ lx_call_user_handler(int sig, siginfo_t *sip, void *p)
{
void (*user_handler)();
void (*stk_builder)();
- struct lx_sigaction *lxsap;
+ volatile struct lx_sigaction *lxsap;
ucontext_t *ucp = (ucontext_t *)p;
size_t stksize;
int lx_sig;
@@ -1480,9 +1480,30 @@ lx_call_user_handler(int sig, siginfo_t *sip, void *p)
assert(0);
}
- if (lxsap->lxsa_handler == SIG_DFL || lxsap->lxsa_handler == SIG_IGN)
+ while (lxsap->lxsa_handler == SIG_DFL ||
+ lxsap->lxsa_handler == SIG_IGN) {
+ /*
+ * This normally shouldn't be possible, but there is a window
+ * in which a vfork()'d process can have its signal disposition
+ * corrupted by its child. While this window is narrowed by
+ * blocking all signals in the brand, that leaves a (smaller)
+ * window whereby a signal in flight is delivered before the
+ * brand has blocked them. To detect this case, we will spin
+ * if our signal disposition is impossible and all signals are
+ * blocked due to vfork() activity: we know that the vfork()'d
+ * child will eventually restore the signal disposition before
+ * it unblocks signals, allowing us to proceed.
+ */
+ if (lx_all_signals_blocked())
+ continue;
+
+ if (lxsap->lxsa_handler != SIG_DFL &&
+ lxsap->lxsa_handler != SIG_IGN)
+ break;
+
lx_err_fatal("lxsa_handler set to %s? How?!?!?",
(lxsap->lxsa_handler == SIG_DFL) ? "SIG_DFL" : "SIG_IGN");
+ }
#if defined(_LP64)
stksize = sizeof (struct lx_sigstack);
@@ -1506,7 +1527,7 @@ lx_call_user_handler(int sig, siginfo_t *sip, void *p)
lxsap->lxsa_handler = SIG_DFL;
lx_sigdeliver(lx_sig, sip, ucp, stksize, stk_builder, user_handler,
- lxsap);
+ (struct lx_sigaction *)lxsap);
/*
* We need to handle restarting system calls if requested by the
@@ -2390,3 +2411,9 @@ lx_unblock_all_signals()
{
(void) syscall(SYS_brand, B_UNBLOCK_ALL_SIGS);
}
+
+int
+lx_all_signals_blocked()
+{
+ return (syscall(SYS_brand, B_ALL_SIGS_BLOCKED));
+}
diff --git a/usr/src/lib/brand/lx/lx_brand/sys/lx_misc.h b/usr/src/lib/brand/lx/lx_brand/sys/lx_misc.h
index ce241db8bc..455ac174df 100644
--- a/usr/src/lib/brand/lx/lx_brand/sys/lx_misc.h
+++ b/usr/src/lib/brand/lx/lx_brand/sys/lx_misc.h
@@ -25,7 +25,7 @@
*/
/*
- * Copyright 2017 Joyent, Inc.
+ * Copyright 2018 Joyent, Inc.
*/
#ifndef _SYS_LX_H
@@ -149,6 +149,7 @@ extern void lx_stack_postfork(void);
extern void lx_block_all_signals();
extern void lx_unblock_all_signals();
+extern int lx_all_signals_blocked();
/*
* NO_UUCOPY disables calls to the uucopy* system calls to help with
diff --git a/usr/src/uts/common/brand/lx/os/lx_brand.c b/usr/src/uts/common/brand/lx/os/lx_brand.c
index 974c8603e0..d388b14c70 100644
--- a/usr/src/uts/common/brand/lx/os/lx_brand.c
+++ b/usr/src/uts/common/brand/lx/os/lx_brand.c
@@ -25,7 +25,7 @@
*/
/*
- * Copyright 2017, Joyent, Inc. All rights reserved.
+ * Copyright 2018, Joyent, Inc. All rights reserved.
*/
/*
@@ -1892,6 +1892,16 @@ lx_brandsys(int cmd, int64_t *rval, uintptr_t arg1, uintptr_t arg2,
mutex_exit(&p->p_lock);
return (result);
}
+
+ case B_ALL_SIGS_BLOCKED: {
+ uint_t result;
+
+ mutex_enter(&p->p_lock);
+ pd = ptolxproc(p);
+ result = pd->l_block_all_signals;
+ mutex_exit(&p->p_lock);
+ return (result);
+ }
}
return (EINVAL);
diff --git a/usr/src/uts/common/brand/lx/sys/lx_brand.h b/usr/src/uts/common/brand/lx/sys/lx_brand.h
index e30568086d..9c1579cc82 100644
--- a/usr/src/uts/common/brand/lx/sys/lx_brand.h
+++ b/usr/src/uts/common/brand/lx/sys/lx_brand.h
@@ -103,7 +103,7 @@ extern "C" {
#define B_STORE_ARGS 137
#define B_GETPID 138
#define B_JUMP_TO_LINUX 139
-/* formerly B_SET_THUNK_PID 140 */
+#define B_ALL_SIGS_BLOCKED 140
#define B_EXIT_AS_SIG 141
/* formerly B_HELPER_WAITID 142 */
#define B_HELPER_CLONE 143