From 68d8769159b2f630ea512527267e9c7aadfbbcee Mon Sep 17 00:00:00 2001 From: deraadt Date: Sat, 10 Oct 2015 22:36:06 +0000 Subject: [PATCH] pflogd contained the same "privsep error" as tcpdump -- assuming that it can ioctl()'s against a bpf device node. Privsep that operation via a message to the parent process. Unfortunately "rpath wpath cpath" is still needed due to SIGHUP handling, but I have asked canacar the expert to look into this. --- sbin/pflogd/pflogd.c | 13 +++++++--- sbin/pflogd/pflogd.h | 3 ++- sbin/pflogd/privsep.c | 57 +++++++++++++++++++++++++++++++++++++------ 3 files changed, 61 insertions(+), 12 deletions(-) diff --git a/sbin/pflogd/pflogd.c b/sbin/pflogd/pflogd.c index be063121bcf..1b6354b4cdf 100644 --- a/sbin/pflogd/pflogd.c +++ b/sbin/pflogd/pflogd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pflogd.c,v 1.51 2015/02/07 02:09:13 deraadt Exp $ */ +/* $OpenBSD: pflogd.c,v 1.52 2015/10/10 22:36:06 deraadt Exp $ */ /* * Copyright (c) 2001 Theo de Raadt @@ -561,8 +561,9 @@ void log_pcap_stats(void) { struct pcap_stat pstat; - if (pcap_stats(hpcap, &pstat) < 0) - logmsg(LOG_WARNING, "Reading stats: %s", pcap_geterr(hpcap)); + + if (priv_pcap_stats(&pstat) < 0) + logmsg(LOG_WARNING, "Reading stats: error"); else logmsg(LOG_NOTICE, "%u packets received, %u/%u dropped (kernel/pflogd)", @@ -655,6 +656,12 @@ main(int argc, char **argv) exit(1); } + /* + * XXX needs wpath cpath rpath, for try_reset_dump() ? + */ + if (pledge("stdio rpath wpath cpath unix recvfd", NULL) == -1) + err(1, "pledge"); + setproctitle("[initializing]"); /* Process is now unprivileged and inside a chroot */ signal(SIGTERM, sig_close); diff --git a/sbin/pflogd/pflogd.h b/sbin/pflogd/pflogd.h index c7ef80e67b0..7bab61167de 100644 --- a/sbin/pflogd/pflogd.h +++ b/sbin/pflogd/pflogd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: pflogd.h,v 1.4 2010/09/21 05:56:58 henning Exp $ */ +/* $OpenBSD: pflogd.h,v 1.5 2015/10/10 22:36:06 deraadt Exp $ */ /* * Copyright (c) 2003 Can Erkin Acar @@ -38,6 +38,7 @@ int priv_init(void); int priv_set_snaplen(int snaplen); int priv_open_log(void); int priv_move_log(void); +int priv_pcap_stats(struct pcap_stat *); pcap_t *pcap_open_live_fd(int fd, int snaplen, char *ebuf); void set_pcap_filter(void); diff --git a/sbin/pflogd/privsep.c b/sbin/pflogd/privsep.c index bb051064c5c..03f86fa99e7 100644 --- a/sbin/pflogd/privsep.c +++ b/sbin/pflogd/privsep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: privsep.c,v 1.20 2015/04/28 05:54:31 mlarkin Exp $ */ +/* $OpenBSD: privsep.c,v 1.21 2015/10/10 22:36:06 deraadt Exp $ */ /* * Copyright (c) 2003 Can Erkin Acar @@ -42,7 +42,8 @@ enum cmd_types { PRIV_SET_SNAPLEN, /* set the snaplength */ PRIV_MOVE_LOG, /* move logfile away */ - PRIV_OPEN_LOG /* open logfile for appending */ + PRIV_OPEN_LOG, /* open logfile for appending */ + PRIV_PCAP_STATS /* get pcap statistics */ }; static int priv_fd = -1; @@ -65,8 +66,9 @@ extern pcap_t *hpcap; int priv_init(void) { - int i, fd, socks[2], cmd; + int i, bpfd = -1, socks[2], cmd; int snaplen, ret, olderrno; + struct pcap_stat stats; struct passwd *pw; for (i = 1; i < _NSIG; i++) @@ -118,6 +120,12 @@ priv_init(void) setproctitle("[priv]"); close(socks[1]); + +#if notyet + /* This needs to do bpf ioctl */ + if (pledge("stdio rpath wpath cpath ioctl sendfd", NULL) == -1) + err(1, "pledge"); +#endif while (!gotsig_chld) { if (may_read(socks[0], &cmd, sizeof(int))) break; @@ -141,17 +149,19 @@ priv_init(void) logmsg(LOG_DEBUG, "[priv]: msg PRIV_OPEN_LOG received"); /* create or append logs but do not follow symlinks */ - fd = open(filename, + if (bpfd != -1) { + close(bpfd); + bpfd = -1; + } + bpfd = open(filename, O_RDWR|O_CREAT|O_APPEND|O_NONBLOCK|O_NOFOLLOW, 0600); olderrno = errno; - send_fd(socks[0], fd); - if (fd < 0) + send_fd(socks[0], bpfd); + if (bpfd < 0) logmsg(LOG_NOTICE, "[priv]: failed to open %s: %s", filename, strerror(olderrno)); - else - close(fd); break; case PRIV_MOVE_LOG: @@ -161,6 +171,19 @@ priv_init(void) must_write(socks[0], &ret, sizeof(int)); break; + case PRIV_PCAP_STATS: + if (ioctl(bpfd, BIOCGSTATS, &stats) == -1) { + int rval = -1; + memset(&stats, 0, sizeof stats); + must_write(socks[0], &stats, sizeof(stats)); + must_write(socks[0], &rval, sizeof(rval)); + } else { + int rval = 0; + must_write(socks[0], &stats, sizeof(stats)); + must_write(socks[0], &rval, sizeof(rval)); + } + break; + default: logmsg(LOG_ERR, "[priv]: unknown command %d", cmd); _exit(1); @@ -265,6 +288,7 @@ priv_open_log(void) return (fd); } + /* Move-away and reopen log-file */ int priv_move_log(void) @@ -281,6 +305,23 @@ priv_move_log(void) return (ret); } +/* Get statistics */ +int +priv_pcap_stats(struct pcap_stat *ps) +{ + int cmd, ret; + + if (priv_fd < 0) + errx(1, "%s: called from privileged portion", __func__); + + cmd = PRIV_PCAP_STATS; + must_write(priv_fd, &cmd, sizeof (int)); + must_read(priv_fd, ps, sizeof(*ps)); + must_read(priv_fd, &ret, sizeof(ret)); + + return (ret); +} + /* If priv parent gets a TERM or HUP, pass it through to child instead */ static void sig_pass_to_chld(int sig) -- 2.20.1