This moves the BIOCGSTATS ioctl operation done by the tcpdump process
(at ^C time, but not at -c count expiration) into a service provided
by the privsep monitor.

Had a bit of help from canacar, who wrote the original privsep code
with otto.

Will be needed for "tame".

Index: privsep.c
===================================================================
RCS file: /cvs/src/usr.sbin/tcpdump/privsep.c,v
retrieving revision 1.33
diff -u -p -u -r1.33 privsep.c
--- privsep.c   15 Mar 2015 00:41:28 -0000      1.33
+++ privsep.c   12 Jul 2015 05:42:29 -0000
@@ -20,6 +20,7 @@
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <sys/wait.h>
+#include <sys/ioctl.h>
 
 #include <netinet/in.h>
 #include <net/if.h>
@@ -59,7 +60,8 @@ enum priv_state {
        STATE_INIT,             /* initial state */
        STATE_BPF,              /* input file/device opened */
        STATE_FILTER,           /* filter applied */
-       STATE_RUN               /* running and accepting network traffic */
+       STATE_RUN,              /* running and accepting network traffic */
+       STATE_EXIT              /* in the process of dying */
 };
 
 #define ALLOW(action)  (1 << (action))
@@ -76,7 +78,8 @@ static const int allowed_max[] = {
                        ALLOW(PRIV_ETHER_NTOHOST) | ALLOW(PRIV_INIT_DONE),
        /* RUN */       ALLOW(PRIV_GETHOSTBYADDR) | ALLOW(PRIV_ETHER_NTOHOST) |
                        ALLOW(PRIV_GETRPCBYNUMBER) | ALLOW(PRIV_GETLINES) |
-                       ALLOW(PRIV_LOCALTIME)
+                       ALLOW(PRIV_LOCALTIME) | ALLOW(PRIV_PCAP_STATS),
+       /* EXIT */      0
 };
 
 /*
@@ -87,7 +90,9 @@ static int allowed_ext[] = {
        /* INIT */      ALLOW(PRIV_SETFILTER),
        /* BPF */       ALLOW(PRIV_SETFILTER),
        /* FILTER */    ALLOW(PRIV_GETSERVENTRIES),
-       /* RUN */       ALLOW(PRIV_GETLINES) | ALLOW(PRIV_LOCALTIME)
+       /* RUN */       ALLOW(PRIV_GETLINES) | ALLOW(PRIV_LOCALTIME) |
+                       ALLOW(PRIV_PCAP_STATS),
+       /* EXIT */      0
 };
 
 struct ftab {
@@ -120,6 +125,7 @@ static void impl_getserventries(int);
 static void    impl_getprotoentries(int);
 static void    impl_localtime(int fd);
 static void    impl_getlines(int);
+static void    impl_pcap_stats(int, int *);
 
 static void    test_state(int, int);
 static void    logmsg(int, const char *, ...);
@@ -186,6 +192,7 @@ priv_init(int argc, char **argv)
        }
 
        sigprocmask(SIG_SETMASK, &oset, NULL);
+       signal(SIGINT, SIG_IGN);
 
        /* Child - drop suid privileges */
        gid = getgid();
@@ -303,6 +310,10 @@ priv_init(int argc, char **argv)
                        test_state(cmd, STATE_RUN);
                        impl_getlines(socks[0]);
                        break;
+               case PRIV_PCAP_STATS:
+                       test_state(cmd, STATE_RUN);
+                       impl_pcap_stats(socks[0], &bpfd);
+                       break;
                default:
                        logmsg(LOG_ERR, "[priv]: unknown command %d", cmd);
                        _exit(1);
@@ -390,8 +401,6 @@ impl_setfilter(int fd, char *cmdbuf, int
 
        if (setfilter(*bpfd, fd, cmdbuf))
                logmsg(LOG_DEBUG, "[priv]: setfilter() failed");
-       close(*bpfd);   /* done with bpf descriptor */
-       *bpfd = -1;
 }
 
 static void
@@ -401,8 +410,6 @@ impl_init_done(int fd, int *bpfd)
 
        logmsg(LOG_DEBUG, "[priv]: msg PRIV_INIT_DONE received");
 
-       close(*bpfd);   /* done with bpf descriptor */
-       *bpfd = -1;
        ret = 0;
        must_write(fd, &ret, sizeof(ret));
 }
@@ -581,6 +588,19 @@ impl_getlines(int fd)
        fclose(fp);
 }
 
+static void
+impl_pcap_stats(int fd, int *bpfd)
+{
+       struct pcap_stat stats;
+
+       logmsg(LOG_DEBUG, "[priv]: msg PRIV_PCAP_STATS received");
+
+       if (ioctl(*bpfd, BIOCGSTATS, &stats) == -1)
+               write_zero(fd);
+       else
+               must_write(fd, &stats, sizeof(stats));
+}
+
 void
 priv_init_done(void)
 {
@@ -738,6 +758,17 @@ priv_getlines(size_t sz)
 
        write_command(priv_fd, PRIV_GETLINES);
        must_write(priv_fd, &sz, sizeof(size_t));
+}
+
+int
+priv_pcap_stats(struct pcap_stat *ps)
+{
+       if (priv_fd < 0)
+               errx(1, "%s: called from privileged portion", __func__);
+
+       write_command(priv_fd, PRIV_PCAP_STATS);
+       must_read(priv_fd, ps, sizeof(*ps));
+       return (0);
 }
 
 /* retrieve a line from a file, should be called repeatedly after calling
Index: privsep.h
===================================================================
RCS file: /cvs/src/usr.sbin/tcpdump/privsep.h,v
retrieving revision 1.7
diff -u -p -u -r1.7 privsep.h
--- privsep.h   25 Aug 2009 06:59:17 -0000      1.7
+++ privsep.h   21 May 2015 01:27:53 -0000
@@ -37,7 +37,8 @@ enum cmd_types {
        PRIV_GETPROTOENTRIES,   /* get the ip protocol entries table */
        PRIV_LOCALTIME,         /* return localtime */
        PRIV_GETLINES,          /* get lines from a file */
-       PRIV_INIT_DONE          /* signal that the initialization is done */
+       PRIV_INIT_DONE,         /* signal that the initialization is done */
+       PRIV_PCAP_STATS         /* get pcap_stats() results */
 };
 
 struct ether_addr;
@@ -80,6 +81,9 @@ void  priv_getlines(size_t);
 /* Retrieve a single line from a file, should be called repeatedly after
    calling priv_getlines() until it returns zero */
 size_t priv_getline(char *, size_t);
+
+/* Return the pcap statistics upon completion */
+int    priv_pcap_stats(struct pcap_stat *);
 
 pcap_dumper_t *priv_pcap_dump_open(pcap_t *, char *);
 
Index: tcpdump.c
===================================================================
RCS file: /cvs/src/usr.sbin/tcpdump/tcpdump.c,v
retrieving revision 1.70
diff -u -p -u -r1.70 tcpdump.c
--- tcpdump.c   18 Apr 2015 18:28:38 -0000      1.70
+++ tcpdump.c   12 Jul 2015 05:41:57 -0000
@@ -515,7 +515,7 @@ cleanup(int signo)
        /* Can't print the summary if reading from a savefile */
        (void)write(STDERR_FILENO, "\n", 1);
        if (pd != NULL && pcap_file(pd) == NULL) {
-               if (pcap_stats(pd, &stat) < 0) {
+               if (priv_pcap_stats(&stat) < 0) {
                        (void)snprintf(buf, sizeof buf,
                            "pcap_stats: %s\n", pcap_geterr(pd));
                        write(STDERR_FILENO, buf, strlen(buf));

Reply via email to