changeset 18381:0c39f4745dad

OS-4127 lx brand: clone(CLONE_VFORK) followed by sigaction corrupts parent
author Bryan Cantrill <bryan@joyent.com>
date Mon, 30 Mar 2015 23:18:47 +0000
parents 1c328f69e981
children 1798e9cce90e
files usr/src/lib/brand/lx/lx_brand/common/clone.c usr/src/lib/brand/lx/lx_brand/common/signal.c usr/src/lib/brand/lx/lx_brand/sys/lx_signal.h
diffstat 3 files changed, 31 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/lib/brand/lx/lx_brand/common/clone.c	Mon Mar 30 14:49:36 2015 +0000
+++ b/usr/src/lib/brand/lx/lx_brand/common/clone.c	Mon Mar 30 23:18:47 2015 +0000
@@ -421,10 +421,26 @@
 		_sigoff();
 		lx_stack_prefork();
 		if (flags & LX_CLONE_VFORK) {
+			lx_sighandlers_t saved;
+
+			/*
+			 * Because we keep our signal disposition at user-land
+			 * (and in memory), we must prevent it from being
+			 * clobbered should our vforked child change the
+			 * disposition (e.g., via sigaction()) before releasing
+			 * the address space.  We preserve our disposition by
+			 * taking a snapshot of it before the vfork and
+			 * restoring it afterwards -- which we can get away
+			 * with because we know that we aren't executing
+			 * concurrently with our child.
+			 */
+			lx_sighandlers_save(&saved);
 			is_vforked++;
 			rval = vforkx(fork_flags);
-			if (rval != 0)
+			if (rval != 0) {
 				is_vforked--;
+				lx_sighandlers_restore(&saved);
+			}
 		} else {
 			rval = forkx(fork_flags);
 		}
--- a/usr/src/lib/brand/lx/lx_brand/common/signal.c	Mon Mar 30 14:49:36 2015 +0000
+++ b/usr/src/lib/brand/lx/lx_brand/common/signal.c	Mon Mar 30 23:18:47 2015 +0000
@@ -2044,6 +2044,18 @@
 }
 #endif
 
+void
+lx_sighandlers_save(lx_sighandlers_t *saved)
+{
+	bcopy(&lx_sighandlers, saved, sizeof (lx_sighandlers_t));
+}
+
+void
+lx_sighandlers_restore(lx_sighandlers_t *saved)
+{
+	bcopy(saved, &lx_sighandlers, sizeof (lx_sighandlers_t));
+}
+
 int
 lx_siginit(void)
 {
--- a/usr/src/lib/brand/lx/lx_brand/sys/lx_signal.h	Mon Mar 30 14:49:36 2015 +0000
+++ b/usr/src/lib/brand/lx/lx_brand/sys/lx_signal.h	Mon Mar 30 23:18:47 2015 +0000
@@ -292,6 +292,8 @@
     int (*)(const ucontext_t *));
 
 extern int lx_siginit(void);
+extern void lx_sighandlers_save(lx_sighandlers_t *);
+extern void lx_sighandlers_restore(lx_sighandlers_t *);
 
 extern int stol_siginfo(siginfo_t *siginfop, lx_siginfo_t *lx_siginfop);
 extern int stol_status(int);