summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRoy Marples <roy@marples.name>2020-06-02 17:48:34 +0100
committerRoy Marples <roy@marples.name>2020-06-02 17:48:34 +0100
commitb8ed6cdf7919b1fc406634ccd043b1a995c89921 (patch)
tree2c6e067fa0bb59e1fb9f439c1ef2cdcb5a0ec699
parentd3de73d80c7f307bab0278162ff81c3731ac2ce7 (diff)
downloaddhcpcd-b8ed6cdf7919b1fc406634ccd043b1a995c89921.tar.xz
privsep: Access the RDM monotic file via IPC
As we can't get at it in the chroot. While here, harden the file.
-rw-r--r--src/auth.c71
-rw-r--r--src/auth.h6
-rw-r--r--src/dhcp.c4
-rw-r--r--src/dhcp6.c8
-rw-r--r--src/privsep-root.c35
-rw-r--r--src/privsep-root.h1
-rw-r--r--src/privsep.h1
7 files changed, 94 insertions, 32 deletions
diff --git a/src/auth.c b/src/auth.c
index 29c00a9c..38b43116 100644
--- a/src/auth.c
+++ b/src/auth.c
@@ -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 @@ finish:
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 @@ get_next_rdm_monotonic_counter(struct auth *auth)
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 @@ get_next_rdm_monotonic_clock(struct auth *auth)
}
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 @@ get_next_rdm_monotonic(struct auth *auth)
* 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 @@ dhcp_auth_encode(struct auth *auth, const struct token *t,
*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);
diff --git a/src/auth.h b/src/auth.h
index aa668c26..30cc38b3 100644
--- a/src/auth.h
+++ b/src/auth.h
@@ -90,7 +90,11 @@ const struct token * dhcp_auth_validate(struct authstate *,
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
diff --git a/src/dhcp.c b/src/dhcp.c
index d3867741..b309b01c 100644
--- a/src/dhcp.c
+++ b/src/dhcp.c
@@ -1034,7 +1034,7 @@ make_message(struct bootp **bootpm, const struct interface *ifp, uint8_t type)
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 @@ make_message(struct bootp **bootpm, const struct interface *ifp, uint8_t type)
#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
diff --git a/src/dhcp6.c b/src/dhcp6.c
index 1c65ed0c..0e7743e3 100644
--- a/src/dhcp6.c
+++ b/src/dhcp6.c
@@ -881,7 +881,7 @@ dhcp6_makemessage(struct interface *ifp)
#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 @@ dhcp6_update_auth(struct interface *ifp, struct dhcp6_message *m, size_t len)
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
diff --git a/src/privsep-root.c b/src/privsep-root.c
index 4f963d31..ae52c6ed 100644
--- a/src/privsep-root.c
+++ b/src/privsep-root.c
@@ -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 @@ ps_root_dowritefile(const struct dhcpcd_ctx *ctx,
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 @@ ps_root_recvmsgcb(void *arg, struct ps_msghdr *psm, struct msghdr *msg)
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 @@ ps_root_ip6forwarding(struct dhcpcd_ctx *ctx, const char *ifname)
}
#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)
diff --git a/src/privsep-root.h b/src/privsep-root.h
index a56e30af..683e5654 100644
--- a/src/privsep-root.h
+++ b/src/privsep-root.h
@@ -44,6 +44,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_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 *);
diff --git a/src/privsep.h b/src/privsep.h
index 93058225..f1fee41e 100644
--- a/src/privsep.h
+++ b/src/privsep.h
@@ -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