changeset 5526:b1a3d9055662 draft

privsep: Allow logfile reopening in a chroot Now that only the privileged actioneer does the actual logging we can safely reopen the file we are logging to. This also closes and re-opens the syslog connection.
author Roy Marples <roy@marples.name>
date Fri, 30 Oct 2020 14:19:16 +0000
parents 26b5d9bc2985
children 071a9ea18363
files src/dhcpcd.8.in src/dhcpcd.c src/dhcpcd.h src/logerr.c src/logerr.h src/privsep-root.c src/privsep-root.h src/privsep.h
diffstat 8 files changed, 76 insertions(+), 41 deletions(-) [+]
line wrap: on
line diff
--- a/src/dhcpcd.8.in	Fri Oct 30 03:43:51 2020 +0000
+++ b/src/dhcpcd.8.in	Fri Oct 30 14:19:16 2020 +0000
@@ -24,7 +24,7 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.Dd September 2, 2020
+.Dd October 30, 2020
 .Dt DHCPCD 8
 .Os
 .Sh NAME
@@ -846,13 +846,5 @@
 .Sh AUTHORS
 .An Roy Marples Aq Mt roy@marples.name
 .Sh BUGS
-If
-.Nm
-is running in a
-.Xr chroot 2
-then re-opening the
-.Fl Fl logfile
-from SIGUSR2 may not work.
-.Pp
 Please report them to
 .Lk http://roy.marples.name/projects/dhcpcd
--- a/src/dhcpcd.c	Fri Oct 30 03:43:51 2020 +0000
+++ b/src/dhcpcd.c	Fri Oct 30 14:19:16 2020 +0000
@@ -1422,10 +1422,14 @@
 		return;
 	case SIGUSR2:
 		loginfox(sigmsg, "SIGUSR2", "reopening log");
-		/* XXX This may not work that well in a chroot */
-		logclose();
-		if (logopen(ctx->logfile) == -1)
-			logerr(__func__);
+		if (IN_PRIVSEP(ctx)) {
+			if (ps_root_logreopen(ctx) == -1)
+				logerr("ps_root_logreopen");
+		} else {
+			logclose();
+			if (logopen(ctx->logfile) == -1)
+				logerr("logopen");
+		}
 		return;
 	case SIGCHLD:
 		while (waitpid(-1, NULL, WNOHANG) > 0)
@@ -1860,7 +1864,7 @@
 	ctx.dhcp6_wfd = -1;
 #endif
 #ifdef PRIVSEP
-	ctx.ps_root_fd = ctx.ps_syslog_fd = ctx.ps_data_fd = -1;
+	ctx.ps_root_fd = ctx.ps_log_fd = ctx.ps_data_fd = -1;
 	ctx.ps_inet_fd = ctx.ps_control_fd = -1;
 	TAILQ_INIT(&ctx.ps_processes);
 #endif
@@ -2328,6 +2332,7 @@
 	/* We have now forked, setsid, forked once more.
 	 * From this point on, we are the controlling daemon. */
 	ctx.options |= DHCPCD_STARTED;
+	logdebugx("spawned master process on PID %d", getpid());
 	if ((pid = pidfile_lock(ctx.pidfile)) != 0) {
 		logerr("%s: pidfile_lock %d", __func__, pid);
 #ifdef PRIVSEP
--- a/src/dhcpcd.h	Fri Oct 30 03:43:51 2020 +0000
+++ b/src/dhcpcd.h	Fri Oct 30 14:19:16 2020 +0000
@@ -199,7 +199,7 @@
 	struct passwd *ps_user;	/* struct passwd for privsep user */
 	pid_t ps_root_pid;
 	int ps_root_fd;		/* Privileged Actioneer commands */
-	int ps_syslog_fd;	/* syslog(3) wrapper */
+	int ps_log_fd;		/* chroot logging */
 	int ps_data_fd;		/* Data from root spawned processes */
 	struct eloop *ps_eloop;	/* eloop for polling root data */
 	struct ps_process_head ps_processes;	/* List of spawned processes */
--- a/src/logerr.c	Fri Oct 30 03:43:51 2020 +0000
+++ b/src/logerr.c	Fri Oct 30 14:19:16 2020 +0000
@@ -48,14 +48,15 @@
 #endif
 
 /* syslog protocol is 1k message max, RFC 3164 section 4.1 */
-#define LOGERR_SYSLOGBUF	1024 + sizeof(int)
+#define LOGERR_SYSLOGBUF	1024 + sizeof(int) + sizeof(pid_t)
 
 #define UNUSED(a)		(void)(a)
 
 struct logctx {
 	char		 log_buf[BUFSIZ];
 	unsigned int	 log_opts;
-	int		 log_syslogfd;
+	int		 log_fd;
+	pid_t		 log_pid;
 #ifndef SMALL
 	FILE		*log_file;
 #ifdef LOGERR_TAG
@@ -67,7 +68,8 @@
 static struct logctx _logctx = {
 	/* syslog style, but without the hostname or tag. */
 	.log_opts = LOGERR_LOG | LOGERR_LOG_DATE | LOGERR_LOG_PID,
-	.log_syslogfd = -1,
+	.log_fd = -1,
+	.log_pid = 0,
 };
 
 #if defined(__linux__)
@@ -155,7 +157,13 @@
 	log_pid = ((stream == stderr && ctx->log_opts & LOGERR_ERR_PID) ||
 	    (stream != stderr && ctx->log_opts & LOGERR_LOG_PID));
 	if (log_pid) {
-		if ((e = fprintf(stream, "[%d]", getpid())) == -1)
+		pid_t pid;
+
+		if (ctx->log_pid == 0)
+			pid = getpid();
+		else
+			pid = ctx->log_pid;
+		if ((e = fprintf(stream, "[%d]", pid)) == -1)
 			return -1;
 		len += e;
 	}
@@ -206,15 +214,19 @@
 	struct logctx *ctx = &_logctx;
 	int len = 0;
 
-	if (ctx->log_syslogfd != -1) {
+	if (ctx->log_fd != -1) {
 		char buf[LOGERR_SYSLOGBUF];
+		pid_t pid;
 
 		memcpy(buf, &pri, sizeof(pri));
-		len = vsnprintf(buf + sizeof(pri), sizeof(buf) - sizeof(pri),
+		pid = getpid();
+		memcpy(buf + sizeof(pri), &pid, sizeof(pid));
+		len = vsnprintf(buf + sizeof(pri) + sizeof(pid),
+		    sizeof(buf) - sizeof(pri) - sizeof(pid),
 		    fmt, args);
 		if (len != -1)
-			len = (int)write(ctx->log_syslogfd, buf,
-			    ((size_t)++len) + sizeof(pri));
+			len = (int)write(ctx->log_fd, buf,
+			    ((size_t)++len) + sizeof(pri) + sizeof(pid));
 		return len;
 	}
 
@@ -351,24 +363,31 @@
 }
 
 int
-loggetsyslogfd(void)
+loggetfd(void)
 {
 	struct logctx *ctx = &_logctx;
 
-	return ctx->log_syslogfd;
+	return ctx->log_fd;
 }
 
 void
-logsetsyslogfd(int fd)
+logsetfd(int fd)
 {
 	struct logctx *ctx = &_logctx;
 
-	ctx->log_syslogfd = fd;
+	ctx->log_fd = fd;
+#ifndef SMALL
+	if (fd != -1 && ctx->log_file != NULL) {
+		fclose(ctx->log_file);
+		ctx->log_file = NULL;
+	}
+#endif
 }
 
 int
-loghandlesyslogfd(int fd)
+logreadfd(int fd)
 {
+	struct logctx *ctx = &_logctx;
 	char buf[LOGERR_SYSLOGBUF];
 	int len, pri;
 
@@ -376,14 +395,18 @@
 	if (len == -1)
 		return -1;
 
-	/* Ensure we have pri and a terminator */
-	if (len < (int)sizeof(pri) + 1 || buf[len - 1] != '\0') {
+	/* Ensure we have pri, pid and a terminator */
+	if (len < (int)(sizeof(pri) + sizeof(pid_t) + 1) ||
+	    buf[len - 1] != '\0')
+	{
 		errno = EINVAL;
 		return -1;
 	}
 
 	memcpy(&pri, buf, sizeof(pri));
-	logmessage(pri, "%s", buf + sizeof(pri));
+	memcpy(&ctx->log_pid, buf + sizeof(pri), sizeof(ctx->log_pid));
+	logmessage(pri, "%s", buf + sizeof(pri) + sizeof(ctx->log_pid));
+	ctx->log_pid = 0;
 	return len;
 }
 
--- a/src/logerr.h	Fri Oct 30 03:43:51 2020 +0000
+++ b/src/logerr.h	Fri Oct 30 14:19:16 2020 +0000
@@ -76,10 +76,10 @@
 #define logerr(...)	log_err(__VA_ARGS__)
 #define logerrx(...)	log_errx(__VA_ARGS__)
 
-/* For syslog in a chroot */
-int loggetsyslogfd(void);
-void logsetsyslogfd(int);
-int loghandlesyslogfd(int);
+/* For logging in a chroot */
+int loggetfd(void);
+void logsetfd(int);
+int logreadfd(int);
 
 unsigned int loggetopts(void);
 void logsetopts(unsigned int);
--- a/src/privsep-root.c	Fri Oct 30 03:43:51 2020 +0000
+++ b/src/privsep-root.c	Fri Oct 30 14:19:16 2020 +0000
@@ -561,6 +561,10 @@
 			rlen = sizeof(mtime);
 		}
 		break;
+	case PS_LOGREOPEN:
+		logclose();
+		err = logopen(ctx->logfile);
+		break;
 #ifdef AUTH
 	case PS_AUTH_MONORDM:
 		err = ps_root_monordm(data, len);
@@ -781,11 +785,11 @@
 }
 
 static void
-ps_root_syslog(void *arg)
+ps_root_log(void *arg)
 {
 	struct dhcpcd_ctx *ctx = arg;
 
-	if (loghandlesyslogfd(ctx->ps_syslog_fd) == -1)
+	if (logreadfd(ctx->ps_log_fd) == -1)
 		logerr(__func__);
 }
 
@@ -816,9 +820,9 @@
 	    ps_root_startcb, ps_root_signalcb, 0);
 
 	if (pid == 0) {
-		ctx->ps_syslog_fd = logfd[1];
-		if (eloop_event_add(ctx->eloop, ctx->ps_syslog_fd,
-		    ps_root_syslog, ctx) == -1)
+		ctx->ps_log_fd = logfd[1];
+		if (eloop_event_add(ctx->eloop, ctx->ps_log_fd,
+		    ps_root_log, ctx) == -1)
 			return -1;
 		close(logfd[0]);
 		ctx->ps_data_fd = datafd[1];
@@ -827,7 +831,7 @@
 	} else if (pid == -1)
 		return -1;
 
-	logsetsyslogfd(logfd[0]);
+	logsetfd(logfd[0]);
 	close(logfd[1]);
 
 	ctx->ps_data_fd = datafd[0];
@@ -930,6 +934,15 @@
 	return ps_root_readerror(ctx, time, sizeof(*time));
 }
 
+ssize_t
+ps_root_logreopen(struct dhcpcd_ctx *ctx)
+{
+
+	if (ps_sendcmd(ctx, ctx->ps_root_fd, PS_LOGREOPEN, 0, NULL, 0) == -1)
+		return -1;
+	return ps_root_readerror(ctx, NULL, 0);
+}
+
 #ifdef PRIVSEP_GETIFADDRS
 int
 ps_root_getifaddrs(struct dhcpcd_ctx *ctx, struct ifaddrs **ifahead)
--- a/src/privsep-root.h	Fri Oct 30 03:43:51 2020 +0000
+++ b/src/privsep-root.h	Fri Oct 30 14:19:16 2020 +0000
@@ -47,6 +47,7 @@
 ssize_t ps_root_readfile(struct dhcpcd_ctx *, const char *, void *, size_t);
 ssize_t ps_root_writefile(struct dhcpcd_ctx *, const char *, mode_t,
     const void *, size_t);
+ssize_t ps_root_logreopen(struct dhcpcd_ctx *);
 ssize_t ps_root_script(struct dhcpcd_ctx *, const void *, size_t);
 int ps_root_getauthrdm(struct dhcpcd_ctx *, uint64_t *);
 #ifdef PRIVSEP_GETIFADDRS
--- a/src/privsep.h	Fri Oct 30 03:43:51 2020 +0000
+++ b/src/privsep.h	Fri Oct 30 14:19:16 2020 +0000
@@ -52,6 +52,7 @@
 #define	PS_AUTH_MONORDM		0x0017
 #define	PS_CTL			0x0018
 #define	PS_CTL_EOF		0x0019
+#define	PS_LOGREOPEN		0x0020
 
 /* BSD Commands */
 #define	PS_IOCTLLINK		0x0101