changeset 5466:8bf1ce29152c draft

privsep: sandbox the launcher process
author Roy Marples <roy@marples.name>
date Sun, 20 Sep 2020 19:09:08 +0100
parents afa6f810f693
children 49e119831377
files src/dhcpcd.c src/dhcpcd.h src/privsep.c src/privsep.h
diffstat 4 files changed, 40 insertions(+), 25 deletions(-) [+]
line wrap: on
line diff
--- a/src/dhcpcd.c	Sun Sep 20 17:43:31 2020 +0100
+++ b/src/dhcpcd.c	Sun Sep 20 19:09:08 2020 +0100
@@ -1417,16 +1417,7 @@
 	}
 
 	if (sig != SIGCHLD && ctx->options & DHCPCD_FORKED) {
-		if (sig == SIGHUP)
-			return;
-
-		pid_t pid = pidfile_read(ctx->pidfile);
-		if (pid == -1) {
-			if (errno != ENOENT)
-				logerr("%s: pidfile_read",__func__);
-		} else if (pid == 0)
-			logerr("%s: pid cannot be zero", __func__);
-		else if (kill(pid, sig) == -1)
+		if (sig != SIGHUP && kill(ctx->fork_pid, sig) == -1)
 			logerr("%s: kill", __func__);
 		return;
 	}
@@ -1769,9 +1760,16 @@
 {
 	struct dhcpcd_ctx *ctx = arg;
 	int exit_code;
+	bool do_exit;
 	ssize_t len;
 
-	len = read(ctx->fork_fd, &exit_code, sizeof(exit_code));
+	if (ctx->fork_pid == 0) {
+		do_exit = false;
+		len = read(ctx->fork_fd, &ctx->fork_pid, sizeof(ctx->fork_pid));
+	} else {
+		do_exit = true;
+		len = read(ctx->fork_fd, &exit_code, sizeof(exit_code));
+	}
 	if (len == -1) {
 		logerr(__func__);
 		exit_code = EXIT_FAILURE;
@@ -1780,7 +1778,8 @@
 		    __func__, len, sizeof(exit_code));
 		exit_code = EXIT_FAILURE;
 	}
-	eloop_exit(ctx->eloop, exit_code);
+	if (do_exit)
+		eloop_exit(ctx->eloop, exit_code);
 }
 
 static void
@@ -2156,7 +2155,7 @@
 	{
 		ctx.options |= DHCPCD_FORKED; /* pretend child process */
 #ifdef PRIVSEP
-		if (IN_PRIVSEP(&ctx) && ps_mastersandbox(&ctx) == -1)
+		if (IN_PRIVSEP(&ctx) && ps_mastersandbox(&ctx, NULL) == -1)
 			goto exit_failure;
 #endif
 		ifp = calloc(1, sizeof(*ifp));
@@ -2208,12 +2207,9 @@
 			    ctx.options & DHCPCD_DUMPLEASE);
 		if (ctx.control_fd != -1) {
 #ifdef PRIVSEP
-			ctx.options &= ~DHCPCD_FORKED;
-			if (IN_PRIVSEP(&ctx) && ps_mastersandbox(&ctx) == -1) {
-				ctx.options |= DHCPCD_FORKED;
+			if (IN_PRIVSEP(&ctx) &&
+			    ps_mastersandbox(&ctx, NULL) == -1)
 				goto exit_failure;
-			}
-			ctx.options |= DHCPCD_FORKED;
 #endif
 			if (!(ctx.options & DHCPCD_DUMPLEASE))
 				loginfox("sending commands to dhcpcd process");
@@ -2316,6 +2312,9 @@
 			logerr("fork");
 			goto exit_failure;
 		case 0:
+			/* Inform the launcher of our pid as it's chrooted */
+			pid = getpid();
+			write(ctx.fork_fd, &pid, sizeof(pid));
 			break;
 		default:
 			ctx.options |= DHCPCD_FORKED; /* A lie */
@@ -2324,8 +2323,8 @@
 		}
 		break;
 	default:
+		setproctitle("[launcher]");
 		ctx.options |= DHCPCD_FORKED; /* A lie */
-		setproctitle("[launcher]");
 		ctx.fork_fd = fork_fd[0];
 		close(fork_fd[1]);
 #ifdef PRIVSEP_RIGHTS
@@ -2351,6 +2350,11 @@
 				eloop_event_add(ctx.eloop, ctx.stderr_fd,
 				    dhcpcd_stderr_cb, &ctx);
 		}
+#ifdef PRIVSEP
+		if (IN_PRIVSEP(&ctx) &&
+		    ps_mastersandbox(&ctx, "stdio proc") == -1)
+			goto exit_failure;
+#endif
 		goto run_loop;
 	}
 
@@ -2428,7 +2432,7 @@
 	eloop_event_add(ctx.eloop, ctx.link_fd, dhcpcd_handlelink, &ctx);
 
 #ifdef PRIVSEP
-	if (IN_PRIVSEP(&ctx) && ps_mastersandbox(&ctx) == -1)
+	if (IN_PRIVSEP(&ctx) && ps_mastersandbox(&ctx, "stdio route") == -1)
 		goto exit_failure;
 #endif
 
--- a/src/dhcpcd.h	Sun Sep 20 17:43:31 2020 +0100
+++ b/src/dhcpcd.h	Sun Sep 20 19:09:08 2020 +0100
@@ -122,6 +122,7 @@
 	bool stderr_valid;
 	int stderr_fd;	/* FD for logging to stderr */
 	int fork_fd;	/* FD for the fork init signal pipe */
+	pid_t fork_pid;
 	const char *cffile;
 	unsigned long long options;
 	char *logfile;
--- a/src/privsep.c	Sun Sep 20 17:43:31 2020 +0100
+++ b/src/privsep.c	Sun Sep 20 19:09:08 2020 +0100
@@ -118,7 +118,8 @@
 
 	if (!(ctx->options & DHCPCD_FORKED))
 		logdebugx("chrooting to `%s' as %s", pw->pw_dir, pw->pw_name);
-	if (chroot(pw->pw_dir) == -1)
+	if (chroot(pw->pw_dir) == -1 &&
+	    (errno != EPERM || ctx->options & DHCPCD_FORKED))
 		logerr("%s: chroot `%s'", __func__, pw->pw_dir);
 	if (chdir("/") == -1)
 		logerr("%s: chdir `/'", __func__);
@@ -517,11 +518,18 @@
 }
 
 int
-ps_mastersandbox(struct dhcpcd_ctx *ctx)
+ps_mastersandbox(struct dhcpcd_ctx *ctx, const char *_pledge)
 {
 	const char *sandbox = NULL;
+	bool forked;
+	int dropped;
 
-	if (ps_dropprivs(ctx) == -1) {
+	forked = ctx->options & DHCPCD_FORKED;
+	ctx->options &= ~DHCPCD_FORKED;
+	dropped = ps_dropprivs(ctx);
+	if (forked)
+		ctx->options |= DHCPCD_FORKED;
+	if (dropped == -1) {
 		logerr("%s: ps_dropprivs", __func__);
 		return -1;
 	}
@@ -537,7 +545,9 @@
 	}
 #endif
 
-	if (ps_entersandbox("stdio route", &sandbox) == -1) {
+	if (_pledge == NULL)
+		_pledge = "stdio";
+	if (ps_entersandbox(_pledge, &sandbox) == -1) {
 		if (errno == ENOSYS) {
 			if (sandbox != NULL)
 				logwarnx("sandbox unavailable: %s", sandbox);
--- a/src/privsep.h	Sun Sep 20 17:43:31 2020 +0100
+++ b/src/privsep.h	Sun Sep 20 19:09:08 2020 +0100
@@ -175,7 +175,7 @@
 int ps_start(struct dhcpcd_ctx *);
 int ps_stop(struct dhcpcd_ctx *);
 int ps_entersandbox(const char *, const char **);
-int ps_mastersandbox(struct dhcpcd_ctx *);
+int ps_mastersandbox(struct dhcpcd_ctx *, const char *);
 
 int ps_unrollmsg(struct msghdr *, struct ps_msghdr *, const void *, size_t);
 ssize_t ps_sendpsmmsg(struct dhcpcd_ctx *, int,