changeset 5304:04f26d9f1885 draft

privsep: Don't wait for the process to finish when stopping it Instead, wait on receipt of SIGCHLD so we're not blocked.
author Roy Marples <roy@marples.name>
date Thu, 04 Jun 2020 12:15:20 +0100
parents 873d4c26c32a
children 2f87bbd4ac93
files src/dhcpcd.c src/privsep-root.c src/privsep.c
diffstat 3 files changed, 27 insertions(+), 49 deletions(-) [+]
line wrap: on
line diff
--- a/src/dhcpcd.c	Thu Jun 04 11:30:20 2020 +0100
+++ b/src/dhcpcd.c	Thu Jun 04 12:15:20 2020 +0100
@@ -87,6 +87,7 @@
 	SIGHUP,
 	SIGUSR1,
 	SIGUSR2,
+	SIGCHLD,
 };
 const size_t dhcpcd_signals_len = __arraycount(dhcpcd_signals);
 
@@ -1399,7 +1400,7 @@
 	unsigned long long opts;
 	int exit_code;
 
-	if (ctx->options & DHCPCD_FORKED) {
+	if (sig != SIGCHLD && ctx->options & DHCPCD_FORKED) {
 		pid_t pid = pidfile_read(ctx->pidfile);
 		if (pid == -1) {
 			if (errno != ENOENT)
@@ -1445,6 +1446,10 @@
 		if (logopen(ctx->logfile) == -1)
 			logerr(__func__);
 		return;
+	case SIGCHLD:
+		while (waitpid(-1, NULL, WNOHANG) > 0)
+			;
+		return;
 	default:
 		logerrx("received signal %d but don't know what to do with it",
 		    sig);
@@ -2215,7 +2220,6 @@
 		}
 		break;
 	default:
-		waitpid(pid, &i, 0);
 		ctx.options |= DHCPCD_FORKED; /* A lie */
 		ctx.fork_fd = sigpipe[0];
 		close(sigpipe[1]);
--- a/src/privsep-root.c	Thu Jun 04 11:30:20 2020 +0100
+++ b/src/privsep-root.c	Thu Jun 04 12:15:20 2020 +0100
@@ -686,6 +686,13 @@
 	if (sig == SIGINT)
 		return;
 
+	/* Reap children */
+	if (sig == SIGCHLD) {
+		while (waitpid(-1, NULL, WNOHANG) > 0)
+			;
+		return;
+	}
+
 	logerrx("process %d unexpectedly terminating on signal %d",
 	    getpid(), sig);
 	if (ctx->ps_root_pid == getpid()) {
--- a/src/privsep.c	Thu Jun 04 11:30:20 2020 +0100
+++ b/src/privsep.c	Thu Jun 04 12:15:20 2020 +0100
@@ -291,61 +291,28 @@
 int
 ps_dostop(struct dhcpcd_ctx *ctx, pid_t *pid, int *fd)
 {
-	int status;
+	int err = 0;
 
 #ifdef PRIVSEP_DEBUG
 	logdebugx("%s: pid %d fd %d", __func__, *pid, *fd);
 #endif
-	if (*pid == 0)
-		return 0;
-	if (*fd == -1)
-		goto wait;
-
-	eloop_event_delete(ctx->eloop, *fd);
-	if (ps_sendcmd(ctx, *fd, PS_STOP, 0, NULL, 0) == -1 &&
-	    errno != ECONNRESET)
-		logerr(__func__);
-	if (shutdown(*fd, SHUT_RDWR) == -1 && errno != ENOTCONN)
-		logerr(__func__);
-	close(*fd);
-	*fd = -1;
-
-wait:
-	status = 0;
-
-#ifdef HAVE_CAPSICUM
-	unsigned int cap_mode = 0;
-	int cap_err = cap_getmode(&cap_mode);
 
-	if (cap_err == -1) {
-		if (errno != ENOSYS)
-			logerr("%s: cap_getmode", __func__);
-	} else if (cap_mode != 0)
-		goto nowait;
-#endif
-
-	/* Wait for the process to finish */
-	while (waitpid(*pid, &status, 0) == -1) {
-		if (errno != EINTR) {
-			logerr("%s: waitpid", __func__);
-			status = 0;
-			break;
+	if (*fd != -1) {
+		eloop_event_delete(ctx->eloop, *fd);
+		if (ps_sendcmd(ctx, *fd, PS_STOP, 0, NULL, 0) == -1 ||
+		    shutdown(*fd, SHUT_RDWR) == -1)
+		{
+			logerr(__func__);
+			err = -1;
 		}
-#ifdef PRIVSEP_DEBUG
-		else
-			logerr("%s: waitpid ", __func__);
-#endif
+		close(*fd);
+		*fd = -1;
 	}
-#ifdef HAVE_CAPSICUM
-nowait:
-#endif
+
+	/* Don't wait for the process as it may not respond to the shutdown
+	 * request. We'll reap the process on receipt of SIGCHLD. */
 	*pid = 0;
-
-#ifdef PRIVSEP_DEBUG
-	logdebugx("%s: status %d", __func__, status);
-#endif
-
-	return status;
+	return err;
 }
 
 int