From e97a66faa1dbc16555c00fe7a6e206619c0d0efe Mon Sep 17 00:00:00 2001
From: "Dmitry V. Levin" <ldv@altlinux.org>
Date: Sat, 27 May 2017 15:58:54 +0000
Subject: [PATCH] Do not reset SIGCHLD handler in tracees to SIG_DFL

While strace resets SIGCHLD handler to the default action so that
waitpid definitely works without losing track of children, tracees
should not inherit this change.

* strace.c (struct exec_params): Add child_sa field.
(init): When setting SIGCHLD handler to SIG_DFL, save the old handler.
(exec_or_die): Restore SIGCHLD handler if it was different from SIG_DFL
at startup.
* NEWS: Mention this change.
---
 NEWS     |  1 +
 strace.c | 19 +++++++++----------
 2 files changed, 10 insertions(+), 10 deletions(-)

diff --git a/NEWS b/NEWS
index 80479a15..5866e69a 100644
--- a/NEWS
+++ b/NEWS
@@ -4,6 +4,7 @@ Noteworthy changes in release ?.?? (????-??-??)
 * Bug fixes
   * In interactive mode (-I2), those signals that were blocked at startup
     will remain blocked for the whole period of strace execution.
+  * strace no longer resets SIGCHLD handler in tracees to the default action.
 
 Noteworthy changes in release 4.17 (2017-05-24)
 ===============================================
diff --git a/strace.c b/strace.c
index 07d5adac..473572fa 100644
--- a/strace.c
+++ b/strace.c
@@ -1200,6 +1200,7 @@ struct exec_params {
 	gid_t run_egid;
 	char **argv;
 	char *pathname;
+	struct sigaction child_sa;
 };
 static struct exec_params params_for_tracee;
 
@@ -1254,6 +1255,9 @@ exec_or_die(void)
 		alarm(0);
 	}
 
+	if (params_for_tracee.child_sa.sa_handler != SIG_DFL)
+		sigaction(SIGCHLD, &params_for_tracee.child_sa, NULL);
+
 	execv(params->pathname, params->argv);
 	perror_msg_and_die("exec");
 }
@@ -1622,13 +1626,6 @@ init(int argc, char *argv[])
 
 	progname = argv[0] ? argv[0] : "strace";
 
-	/* Make sure SIGCHLD has the default action so that waitpid
-	   definitely works without losing track of children.  The user
-	   should not have given us a bogus state to inherit, but he might
-	   have.  Arguably we should detect SIG_IGN here and pass it on
-	   to children, but probably noone really needs that.  */
-	signal(SIGCHLD, SIG_DFL);
-
 	strace_tracer_pid = getpid();
 
 	os_release = get_os_release();
@@ -1821,6 +1818,11 @@ init(int argc, char *argv[])
 		tflag = 1;
 	}
 
+	sigprocmask(SIG_SETMASK, NULL, &start_set);
+	memcpy(&blocked_set, &start_set, sizeof(blocked_set));
+
+	set_sigaction(SIGCHLD, SIG_DFL, &params_for_tracee.child_sa);
+
 #ifdef USE_LIBUNWIND
 	if (stack_trace_enabled) {
 		unsigned int tcbi;
@@ -1913,9 +1915,6 @@ init(int argc, char *argv[])
 	if (!opt_intr)
 		opt_intr = INTR_WHILE_WAIT;
 
-	sigprocmask(SIG_SETMASK, NULL, &start_set);
-	memcpy(&blocked_set, &start_set, sizeof(blocked_set));
-
 	/*
 	 * startup_child() must be called before the signal handlers get
 	 * installed below as they are inherited into the spawned process.
-- 
2.40.0