On Thu, Jul 18, 2019 at 11:46:46AM -0400, Bryan Steele wrote:
> On Thu, Jul 18, 2019 at 04:13:10PM +0200, Alexander Bluhm wrote:
> > Hi,
> >
> > Can we track unveil(2) violators in process accounting lastcomm(1)?
> > This makes it easier to find them.
> >
> > $ lastcomm | grep -e '-[A-Z]U'
> > pflogd -FU root __ 0.00 secs Thu Jul 18 14:19
> > (2:33:22.00)
> >
> > Seems that pflogd(8) has to be investigated.
>
> Interesting.
>
> This appears to be a false positive, libpcap will first attempt to open
> /dev/bpf as O_RDWR and then falls back to O_RDONLY on EACCES. I'm fairly
> confident that pflogd(8) does not need write access to bpf. If anything,
> unveil(2) appears to have found an old bug here, as before pflogd was
> always opening the device with both read/write permissions.
>
> tcpdump avoids this by internalizing more parts of libpcap, and also
> opening /dev/bpf O_RDONLY itself.
>
> spamlogd appears to be the only other user of pcap_open_live() in base,
> unfortunately it calls unveil after, so /dev/bpf is opened O_RDWR. I
> don't use spamlogd, though.
Here's a potential diff for both pflogd and spamlogd, I've tested it
works with pflogd. I only compile tested spamlogd. But it should avoid
the unveil accounting errors.
This duplicates a lot of code into both, but I don't feel like trying
to extent the libpcap API for this.
comments? ok?
Index: pflogd.c
===================================================================
RCS file: /cvs/src/sbin/pflogd/pflogd.c,v
retrieving revision 1.59
diff -u -p -u -r1.59 pflogd.c
--- sbin/pflogd/pflogd.c 26 Aug 2018 18:24:46 -0000 1.59
+++ sbin/pflogd/pflogd.c 18 Jul 2019 21:30:39 -0000
@@ -73,6 +73,7 @@ void dump_packet(u_char *, const struct
void dump_packet_nobuf(u_char *, const struct pcap_pkthdr *, const u_char *);
int flush_buffer(FILE *);
int if_exists(char *);
+pcap_t *pcap_live(const char *, int, int, int, char *);
void logmsg(int, const char *, ...);
void purge_buffer(void);
int reset_dump(void);
@@ -194,10 +195,97 @@ if_exists(char *ifname)
return (if_nametoindex(ifname) != 0);
}
+pcap_t *
+pcap_live(const char *source, int slen, int promisc, int to_ms,
+ char *ebuf)
+{
+ int fd;
+ struct bpf_version bv;
+ struct ifreq ifr;
+ u_int v, dlt = DLT_PFLOG;
+ pcap_t *p;
+
+ if (source == NULL || slen <= 0)
+ return (NULL);
+
+ p = pcap_create(source, ebuf);
+ if (p == NULL)
+ return (NULL);
+
+ /* Open bpf(4) read only */
+ if ((fd = open("/dev/bpf", O_RDONLY)) == -1)
+ return (NULL);
+
+ if (ioctl(fd, BIOCVERSION, &bv) == -1) {
+ snprintf(ebuf, PCAP_ERRBUF_SIZE, "BIOCVERSION: %s",
+ pcap_strerror(errno));
+ goto bad;
+ }
+
+ if (bv.bv_major != BPF_MAJOR_VERSION ||
+ bv.bv_minor < BPF_MINOR_VERSION) {
+ snprintf(ebuf, PCAP_ERRBUF_SIZE,
+ "kernel bpf filter out of date");
+ goto bad;
+ }
+
+ strlcpy(ifr.ifr_name, source, sizeof(ifr.ifr_name));
+ if (ioctl(fd, BIOCSETIF, &ifr) == -1) {
+ snprintf(ebuf, PCAP_ERRBUF_SIZE, "BIOCSETIF: %s",
+ pcap_strerror(errno));
+ goto bad;
+ }
+
+ if (dlt != (u_int) -1 && ioctl(fd, BIOCSDLT, &dlt)) {
+ snprintf(ebuf, PCAP_ERRBUF_SIZE, "BIOCSDLT: %s",
+ pcap_strerror(errno));
+ goto bad;
+ }
+
+ p->fd = fd;
+ p->snapshot = slen;
+ p->linktype = dlt;
+
+ /* set timeout */
+ if (to_ms != 0) {
+ struct timeval to;
+ to.tv_sec = to_ms / 1000;
+ to.tv_usec = (to_ms * 1000) % 1000000;
+ if (ioctl(p->fd, BIOCSRTIMEOUT, &to) < 0) {
+ snprintf(ebuf, PCAP_ERRBUF_SIZE, "BIOCSRTIMEOUT: %s",
+ pcap_strerror(errno));
+ }
+ }
+ if (promisc)
+ /* this is allowed to fail */
+ ioctl(fd, BIOCPROMISC, NULL);
+
+ if (ioctl(fd, BIOCGBLEN, &v) < 0) {
+ snprintf(ebuf, PCAP_ERRBUF_SIZE, "BIOCGBLEN: %s",
+ pcap_strerror(errno));
+ goto bad;
+ }
+ p->bufsize = v;
+ p->buffer = malloc(p->bufsize);
+ if (p->buffer == NULL) {
+ snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s",
+ pcap_strerror(errno));
+ goto bad;
+ }
+ p->activated = 1;
+ return (p);
+
+bad:
+ if (fd >= 0)
+ close(fd);
+ free(p);
+ return (NULL);
+}
+
int
init_pcap(void)
{
- hpcap = pcap_open_live(interface, snaplen, 1, PCAP_TO_MS, errbuf);
+ hpcap = pcap_live(interface, snaplen, 1, PCAP_TO_MS, errbuf);
if (hpcap == NULL) {
logmsg(LOG_ERR, "Failed to initialize: %s", errbuf);
return (-1);
Index: Makefile
===================================================================
RCS file: /cvs/src/libexec/spamlogd/Makefile,v
retrieving revision 1.8
diff -u -p -u -r1.8 Makefile
--- libexec/spamlogd/Makefile 28 Jun 2018 02:23:27 -0000 1.8
+++ libexec/spamlogd/Makefile 18 Jul 2019 21:37:48 -0000
@@ -5,6 +5,8 @@ SRCS= spamlogd.c sync.c gdcopy.c
MAN= spamlogd.8
CFLAGS+= -Wall -Wstrict-prototypes -I${.CURDIR}/../spamd
+# for pcap-int.h
+CFLAGS+=-I${.CURDIR}/../../lib/libpcap
LDADD+= -lpcap -lcrypto
DPADD+= ${LIBPCAP} ${LIBCRYPTO}
.PATH: ${.CURDIR}/../spamd
Index: spamlogd.c
===================================================================
RCS file: /cvs/src/libexec/spamlogd/spamlogd.c,v
retrieving revision 1.28
diff -u -p -u -r1.28 spamlogd.c
--- libexec/spamlogd/spamlogd.c 25 Oct 2018 06:41:50 -0000 1.28
+++ libexec/spamlogd/spamlogd.c 18 Jul 2019 21:37:48 -0000
@@ -49,6 +49,7 @@
#include <syslog.h>
#include <string.h>
#include <unistd.h>
+#include <pcap-int.h>
#include <pcap.h>
#include "grey.h"
@@ -107,6 +108,93 @@ sighandler_close(int signal)
pcap_breakloop(hpcap); /* sighdlr safe */
}
+pcap_t *
+pcap_live(const char *source, int slen, int promisc, int to_ms,
+ char *ebuf)
+{
+ int fd;
+ struct bpf_version bv;
+ struct ifreq ifr;
+ u_int v, dlt = DLT_PFLOG;
+ pcap_t *p;
+
+ if (source == NULL || slen <= 0)
+ return (NULL);
+
+ p = pcap_create(source, ebuf);
+ if (p == NULL)
+ return (NULL);
+
+ /* Open bpf(4) read only */
+ if ((fd = open("/dev/bpf", O_RDONLY)) == -1)
+ return (NULL);
+
+ if (ioctl(fd, BIOCVERSION, &bv) == -1) {
+ snprintf(ebuf, PCAP_ERRBUF_SIZE, "BIOCVERSION: %s",
+ pcap_strerror(errno));
+ goto bad;
+ }
+
+ if (bv.bv_major != BPF_MAJOR_VERSION ||
+ bv.bv_minor < BPF_MINOR_VERSION) {
+ snprintf(ebuf, PCAP_ERRBUF_SIZE,
+ "kernel bpf filter out of date");
+ goto bad;
+ }
+
+ strlcpy(ifr.ifr_name, source, sizeof(ifr.ifr_name));
+ if (ioctl(fd, BIOCSETIF, &ifr) == -1) {
+ snprintf(ebuf, PCAP_ERRBUF_SIZE, "BIOCSETIF: %s",
+ pcap_strerror(errno));
+ goto bad;
+ }
+
+ if (dlt != (u_int) -1 && ioctl(fd, BIOCSDLT, &dlt)) {
+ snprintf(ebuf, PCAP_ERRBUF_SIZE, "BIOCSDLT: %s",
+ pcap_strerror(errno));
+ goto bad;
+ }
+
+ p->fd = fd;
+ p->snapshot = slen;
+ p->linktype = dlt;
+
+ /* set timeout */
+ if (to_ms != 0) {
+ struct timeval to;
+ to.tv_sec = to_ms / 1000;
+ to.tv_usec = (to_ms * 1000) % 1000000;
+ if (ioctl(p->fd, BIOCSRTIMEOUT, &to) < 0) {
+ snprintf(ebuf, PCAP_ERRBUF_SIZE, "BIOCSRTIMEOUT: %s",
+ pcap_strerror(errno));
+ }
+ }
+ if (promisc)
+ /* this is allowed to fail */
+ ioctl(fd, BIOCPROMISC, NULL);
+
+ if (ioctl(fd, BIOCGBLEN, &v) < 0) {
+ snprintf(ebuf, PCAP_ERRBUF_SIZE, "BIOCGBLEN: %s",
+ pcap_strerror(errno));
+ goto bad;
+ }
+ p->bufsize = v;
+ p->buffer = malloc(p->bufsize);
+ if (p->buffer == NULL) {
+ snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s",
+ pcap_strerror(errno));
+ goto bad;
+ }
+ p->activated = 1;
+ return (p);
+
+bad:
+ if (fd >= 0)
+ close(fd);
+ free(p);
+ return (NULL);
+}
+
int
init_pcap(void)
{
@@ -114,7 +202,7 @@ init_pcap(void)
char filter[PCAPFSIZ] = "ip and port 25 and action pass "
"and tcp[13]&0x12=0x2";
- if ((hpcap = pcap_open_live(pflogif, PCAPSNAP, 1, PCAPTIMO,
+ if ((hpcap = pcap_live(pflogif, PCAPSNAP, 1, PCAPTIMO,
errbuf)) == NULL) {
logmsg(LOG_ERR, "Failed to initialize: %s", errbuf);
return (-1);