changeset 5299:b7e676ac73c1 draft

privsep: Access the RDM monotic file via IPC As we can't get at it in the chroot. While here, harden the file.
author Roy Marples <roy@marples.name>
date Tue, 02 Jun 2020 17:48:34 +0100
parents 95d69db26ac5
children d6366bcea63f
files src/auth.c src/auth.h src/dhcp.c src/dhcp6.c src/privsep-root.c src/privsep-root.h src/privsep.h
diffstat 7 files changed, 94 insertions(+), 32 deletions(-) [+]
line wrap: on
line diff
--- a/src/auth.c	Tue Jun 02 17:07:12 2020 +0100
+++ b/src/auth.c	Tue Jun 02 17:48:34 2020 +0100
@@ -27,6 +27,8 @@
  */
 
 #include <sys/file.h>
+#include <sys/stat.h>
+
 #include <errno.h>
 #include <fcntl.h>
 #include <inttypes.h>
@@ -42,6 +44,7 @@
 #include "dhcp.h"
 #include "dhcp6.h"
 #include "dhcpcd.h"
+#include "privsep-root.h"
 
 #ifdef HAVE_HMAC_H
 #include <hmac.h>
@@ -408,11 +411,11 @@
 	return t;
 }
 
-static uint64_t
-get_next_rdm_monotonic_counter(struct auth *auth)
+int
+auth_get_rdm_monotonic(uint64_t *rdm)
 {
 	FILE *fp;
-	uint64_t rdm;
+	int err;
 #ifdef LOCK_EX
 	int flocked;
 #endif
@@ -420,41 +423,43 @@
 	fp = fopen(RDM_MONOFILE, "r+");
 	if (fp == NULL) {
 		if (errno != ENOENT)
-			return ++auth->last_replay; /* report error? */
+			return -1;
 		fp = fopen(RDM_MONOFILE, "w");
 		if (fp == NULL)
-			return ++auth->last_replay; /* report error? */
+			return -1;
+		if (chmod(RDM_MONOFILE, 0400) == -1) {
+			fclose(fp);
+			unlink(RDM_MONOFILE);
+			return -1;
+		}
 #ifdef LOCK_EX
 		flocked = flock(fileno(fp), LOCK_EX);
 #endif
-		rdm = 0;
+		*rdm = 0;
 	} else {
 #ifdef LOCK_EX
 		flocked = flock(fileno(fp), LOCK_EX);
 #endif
-		if (fscanf(fp, "0x%016" PRIu64, &rdm) != 1)
-			rdm = 0; /* truncated? report error? */
+		if (fscanf(fp, "0x%016" PRIu64, rdm) != 1) {
+			fclose(fp);
+			return -1;
+		}
 	}
 
-	rdm++;
+	(*rdm)++;
 	if (fseek(fp, 0, SEEK_SET) == -1 ||
 	    ftruncate(fileno(fp), 0) == -1 ||
-	    fprintf(fp, "0x%016" PRIu64 "\n", rdm) != 19 ||
+	    fprintf(fp, "0x%016" PRIu64 "\n", *rdm) != 19 ||
 	    fflush(fp) == EOF)
-	{
-		if (!auth->last_replay_set) {
-			auth->last_replay = rdm;
-			auth->last_replay_set = 1;
-		} else
-			rdm = ++auth->last_replay;
-		/* report error? */
-	}
+		err = -1;
+	else
+		err = 0;
 #ifdef LOCK_EX
 	if (flocked == 0)
 		flock(fileno(fp), LOCK_UN);
 #endif
 	fclose(fp);
-	return rdm;
+	return err;
 }
 
 #define	NTP_EPOCH	2208988800U	/* 1970 - 1900 in seconds */
@@ -476,11 +481,26 @@
 }
 
 static uint64_t
-get_next_rdm_monotonic(struct auth *auth)
+get_next_rdm_monotonic(struct dhcpcd_ctx *ctx, struct auth *auth)
 {
 
-	if (auth->options & DHCPCD_AUTH_RDM_COUNTER)
-		return get_next_rdm_monotonic_counter(auth);
+	if (auth->options & DHCPCD_AUTH_RDM_COUNTER) {
+		uint64_t rdm;
+		int err;
+
+#ifdef PRIVSEP
+		if (IN_PRIVSEP(ctx)) {
+
+			err = ps_root_getauthrdm(ctx, &rdm);
+		} else
+#endif
+			err = auth_get_rdm_monotonic(&rdm);
+		if (err == -1)
+			return ++auth->last_replay;
+
+		auth->last_replay = rdm;
+		return rdm;
+	}
 	return get_next_rdm_monotonic_clock(auth);
 }
 
@@ -495,7 +515,8 @@
  * data and dlen refer to the authentication option within the message.
  */
 ssize_t
-dhcp_auth_encode(struct auth *auth, const struct token *t,
+dhcp_auth_encode(struct dhcpcd_ctx *ctx, struct auth *auth,
+    const struct token *t,
     void *vm, size_t mlen, int mp, int mt,
     void *vdata, size_t dlen)
 {
@@ -611,11 +632,11 @@
 		*data++ = auth->rdm;
 		switch (auth->rdm) {
 		case AUTH_RDM_MONOTONIC:
-			rdm = get_next_rdm_monotonic(auth);
+			rdm = get_next_rdm_monotonic(ctx, auth);
 			break;
 		default:
 			/* This block appeases gcc, clang doesn't need it */
-			rdm = get_next_rdm_monotonic(auth);
+			rdm = get_next_rdm_monotonic(ctx, auth);
 			break;
 		}
 		rdm = htonll(rdm);
--- a/src/auth.h	Tue Jun 02 17:07:12 2020 +0100
+++ b/src/auth.h	Tue Jun 02 17:48:34 2020 +0100
@@ -90,7 +90,11 @@
     const void *, size_t, int, int,
     const void *, size_t);
 
-ssize_t dhcp_auth_encode(struct auth *, const struct token *,
+struct dhcpcd_ctx;
+ssize_t dhcp_auth_encode(struct dhcpcd_ctx *, struct auth *,
+    const struct token *,
     void *, size_t, int, int,
     void *, size_t);
+
+int auth_get_rdm_monotonic(uint64_t *rdm);
 #endif
--- a/src/dhcp.c	Tue Jun 02 17:07:12 2020 +0100
+++ b/src/dhcp.c	Tue Jun 02 17:48:34 2020 +0100
@@ -1034,7 +1034,7 @@
 	auth = NULL;	/* appease GCC */
 	auth_len = 0;
 	if (ifo->auth.options & DHCPCD_AUTH_SEND) {
-		ssize_t alen = dhcp_auth_encode(&ifo->auth,
+		ssize_t alen = dhcp_auth_encode(ifp->ctx, &ifo->auth,
 		    state->auth.token,
 		    NULL, 0, 4, type, NULL, 0);
 		if (alen != -1 && alen > UINT8_MAX) {
@@ -1129,7 +1129,7 @@
 
 #ifdef AUTH
 	if (ifo->auth.options & DHCPCD_AUTH_SEND && auth_len != 0)
-		dhcp_auth_encode(&ifo->auth, state->auth.token,
+		dhcp_auth_encode(ifp->ctx, &ifo->auth, state->auth.token,
 		    (uint8_t *)bootp, len, 4, type, auth, auth_len);
 #endif
 
--- a/src/dhcp6.c	Tue Jun 02 17:07:12 2020 +0100
+++ b/src/dhcp6.c	Tue Jun 02 17:48:34 2020 +0100
@@ -881,7 +881,7 @@
 #ifdef AUTH
 	auth_len = 0;
 	if (ifo->auth.options & DHCPCD_AUTH_SEND) {
-		ssize_t alen = dhcp_auth_encode(&ifo->auth,
+		ssize_t alen = dhcp_auth_encode(ifp->ctx, &ifo->auth,
 		    state->auth.token, NULL, 0, 6, type, NULL, 0);
 		if (alen != -1 && alen > UINT16_MAX) {
 			errno = ERANGE;
@@ -1196,9 +1196,9 @@
 		return -1;
 
 	state = D6_STATE(ifp);
-	return dhcp_auth_encode(&ifp->options->auth, state->auth.token,
-	    (uint8_t *)state->send, state->send_len,
-	    6, state->send->type, opt, opt_len);
+	return dhcp_auth_encode(ifp->ctx, &ifp->options->auth,
+	    state->auth.token, (uint8_t *)state->send, state->send_len, 6,
+	    state->send->type, opt, opt_len);
 }
 #endif
 
--- a/src/privsep-root.c	Tue Jun 02 17:07:12 2020 +0100
+++ b/src/privsep-root.c	Tue Jun 02 17:48:34 2020 +0100
@@ -43,6 +43,7 @@
 #include <string.h>
 #include <unistd.h>
 
+#include "auth.h"
 #include "common.h"
 #include "dev.h"
 #include "dhcpcd.h"
@@ -333,6 +334,19 @@
 	return writefile(file, mode, nc, len - (size_t)(nc - file));
 }
 
+#ifdef AUTH
+static ssize_t
+ps_root_monordm(uint64_t *rdm, size_t len)
+{
+
+	if (len != sizeof(*rdm)) {
+		errno = EINVAL;
+		return -1;
+	}
+	return auth_get_rdm_monotonic(rdm);
+}
+#endif
+
 #ifdef HAVE_CAPSICUM
 #define	IFA_NADDRS	3
 static ssize_t
@@ -537,6 +551,15 @@
 			rlen = sizeof(mtime);
 		}
 		break;
+#ifdef AUTH
+	case PS_AUTH_MONORDM:
+		err = ps_root_monordm(data, len);
+		if (err != -1) {
+			rdata = data;
+			rlen = len;
+		}
+		break;
+#endif
 #ifdef HAVE_CAPSICUM
 	case PS_GETIFADDRS:
 		err = ps_root_dogetifaddrs(&rdata, &rlen);
@@ -937,6 +960,18 @@
 }
 #endif
 
+#ifdef AUTH
+int
+ps_root_getauthrdm(struct dhcpcd_ctx *ctx, uint64_t *rdm)
+{
+
+	if (ps_sendcmd(ctx, ctx->ps_root_fd, PS_AUTH_MONORDM, 0,
+	    rdm, sizeof(rdm))== -1)
+		return -1;
+	return (int)ps_root_readerror(ctx, rdm, sizeof(*rdm));
+}
+#endif
+
 #ifdef PLUGIN_DEV
 int
 ps_root_dev_initialized(struct dhcpcd_ctx *ctx, const char *ifname)
--- a/src/privsep-root.h	Tue Jun 02 17:07:12 2020 +0100
+++ b/src/privsep-root.h	Tue Jun 02 17:48:34 2020 +0100
@@ -44,6 +44,7 @@
 ssize_t ps_root_writefile(struct dhcpcd_ctx *, const char *, mode_t,
     const void *, size_t);
 ssize_t ps_root_script(struct dhcpcd_ctx *, const void *, size_t);
+int ps_root_getauthrdm(struct dhcpcd_ctx *, uint64_t *);
 int ps_root_getifaddrs(struct dhcpcd_ctx *, struct ifaddrs **);
 
 ssize_t ps_root_os(struct ps_msghdr *, struct msghdr *);
--- a/src/privsep.h	Tue Jun 02 17:07:12 2020 +0100
+++ b/src/privsep.h	Tue Jun 02 17:48:34 2020 +0100
@@ -49,6 +49,7 @@
 #define	PS_READFILE		0x0014
 #define	PS_WRITEFILE		0x0015
 #define	PS_FILEMTIME		0x0016
+#define	PS_AUTH_MONORDM		0x0017
 
 /* BSD Commands */
 #define	PS_IOCTLLINK		0x0101