tcpdump mailing list archives

FreeBSD sandboxing support via capsicum


From: Loganaden Velvindron <logan () elandsys com>
Date: Sat, 5 Jul 2014 13:15:06 -0700

Hi All,

FreeBSD has designed capsicum which is a sandboxing mechanism.

Please find below a patch against FreeBSD 10 Release:

(Patch based on FreeBSD's port of tcpdump done by pjd () freebsd org)

diff --git a/tcpdump.c b/tcpdump.c
index 739f9c8..aaac4b8 100644
--- a/tcpdump.c
+++ b/tcpdump.c
@@ -66,6 +66,13 @@ extern int SIZE_BUF;
 #include <stdlib.h>
 #include <string.h>
 #include <limits.h>
+#ifdef __FreeBSD__
+#include <sys/capability.h>
+#include <sys/ioccom.h>
+#include <net/bpf.h>
+#include <fcntl.h>
+#include <libgen.h>
+#endif /* __FreeBSD__ */
 #ifndef WIN32
 #include <sys/wait.h>
 #include <sys/resource.h>
@@ -388,6 +395,9 @@ struct dump_info {
        char    *CurrentFileName;
        pcap_t  *pd;
        pcap_dumper_t *p;
+#ifdef __FreeBSD__
+       int     dirfd;
+#endif
 };
 
 #ifdef HAVE_PCAP_SET_TSTAMP_TYPE
@@ -712,6 +722,11 @@ main(int argc, char **argv)
 #endif
        int status;
        FILE *VFile;
+#ifdef __FreeBSD__
+       cap_rights_t rights;
+       int cansandbox;
+#endif /* __FreeBSD__ */
+
 #ifdef WIN32
        if(wsockinit() != 0) return 1;
 #endif /* WIN32 */
@@ -1216,6 +1231,13 @@ main(int argc, char **argv)
                pd = pcap_open_offline(RFileName, ebuf);
                if (pd == NULL)
                        error("%s", ebuf);
+#ifdef __FreeBSD__
+               cap_rights_init(&rights, CAP_READ);
+               if (cap_rights_limit(fileno(pcap_file(pd)), &rights) < 0 &&
+                   errno != ENOSYS) {
+                       error("unable to limit pcap descriptor");
+               }
+#endif
                dlt = pcap_datalink(pd);
                dlt_name = pcap_datalink_val_to_name(dlt);
                if (dlt_name == NULL) {
@@ -1472,6 +1494,21 @@ main(int argc, char **argv)
 
        if (pcap_setfilter(pd, &fcode) < 0)
                error("%s", pcap_geterr(pd));
+#ifdef __FreeBSD__
+       if (RFileName == NULL && VFileName == NULL) {
+               static const unsigned long cmds[] = { BIOCGSTATS };
+
+               cap_rights_init(&rights, CAP_IOCTL, CAP_READ);
+               if (cap_rights_limit(pcap_fileno(pd), &rights) < 0 &&
+                   errno != ENOSYS) {
+                       error("unable to limit pcap descriptor");
+               }
+               if (cap_ioctls_limit(pcap_fileno(pd), cmds,
+                   sizeof(cmds) / sizeof(cmds[0])) < 0 && errno != ENOSYS) {
+                       error("unable to limit ioctls on pcap descriptor");
+               }
+       }
+#endif
        if (WFileName) {
                pcap_dumper_t *p;
                /* Do not exceed the default PATH_MAX for files. */
@@ -1493,9 +1530,32 @@ main(int argc, char **argv)
 #endif
                if (p == NULL)
                        error("%s", pcap_geterr(pd));
+#ifdef __FreeBSD__
+               cap_rights_init(&rights, CAP_SEEK, CAP_WRITE);
+               if (cap_rights_limit(fileno(pcap_dump_file(p)), &rights) < 0 &&
+                   errno != ENOSYS) {
+                       error("unable to limit dump descriptor");
+               }
+#endif
                if (Cflag != 0 || Gflag != 0) {
-                       callback = dump_packet_and_trunc;
+#ifdef __FreeBSD__
+                       dumpinfo.WFileName = strdup(basename(WFileName));
+                       dumpinfo.dirfd = open(dirname(WFileName),
+                           O_DIRECTORY | O_RDONLY);
+                       if (dumpinfo.dirfd < 0) {
+                               error("unable to open directory %s",
+                                   dirname(WFileName));
+                       }
+                       cap_rights_init(&rights, CAP_CREATE, CAP_FCNTL,
+                           CAP_FTRUNCATE, CAP_LOOKUP, CAP_SEEK, CAP_WRITE);
+                       if (cap_rights_limit(dumpinfo.dirfd, &rights) < 0 &&
+                           errno != ENOSYS) {
+                               error("unable to limit directory rights");
+                       }
+#else  /* !__FreeBSD__ */
                        dumpinfo.WFileName = WFileName;
+#endif
+                       callback = dump_packet_and_trunc;
                        dumpinfo.pd = pd;
                        dumpinfo.p = p;
                        pcap_userdata = (u_char *)&dumpinfo;
@@ -1565,6 +1625,15 @@ main(int argc, char **argv)
                (void)fflush(stderr);
        }
 #endif /* WIN32 */
+
+#ifdef __FreeBSD__
+       cansandbox = (nflag && VFileName == NULL && zflag == NULL);
+       if (cansandbox && cap_enter() < 0 && errno != ENOSYS)
+               error("unable to enter the capability mode");
+       if (cap_sandboxed())
+               fprintf(stderr, "capability mode sandbox enabled\n");
+#endif /* __FreeBSD__ */
+
        do {
                status = pcap_loop(pd, cnt, callback, pcap_userdata);
                if (WFileName == NULL) {
@@ -1612,6 +1681,13 @@ main(int argc, char **argv)
                                pd = pcap_open_offline(RFileName, ebuf);
                                if (pd == NULL)
                                        error("%s", ebuf);
+#ifdef __FreeBSD__
+                               cap_rights_init(&rights, CAP_READ);
+                               if (cap_rights_limit(fileno(pcap_file(pd)),
+                                   &rights) < 0 && errno != ENOSYS) {
+                                       error("unable to limit pcap descriptor");
+                               }
+#endif
                                new_dlt = pcap_datalink(pd);
                                if (WFileName && new_dlt != dlt)
                                        error("%s: new dlt does not match original", RFileName);
@@ -1780,6 +1856,9 @@ static void
 dump_packet_and_trunc(u_char *user, const struct pcap_pkthdr *h, const u_char *sp)
 {
        struct dump_info *dump_info;
+#ifdef __FreeBSD__
+       cap_rights_t rights;
+#endif
 
        ++packets_captured;
 
@@ -1808,6 +1887,11 @@ dump_packet_and_trunc(u_char *user, const struct pcap_pkthdr *h, const u_char *s
 
                /* If the time is greater than the specified window, rotate */
                if (t - Gflag_time >= Gflag) {
+#ifdef __FreeBSD__
+                       FILE *fp;
+                       int fd;
+#endif
+
                        /* Update the Gflag_time */
                        Gflag_time = t;
                        /* Update Gflag_count */
@@ -1854,13 +1938,36 @@ dump_packet_and_trunc(u_char *user, const struct pcap_pkthdr *h, const u_char *s
                        capng_update(CAPNG_ADD, CAPNG_EFFECTIVE, CAP_DAC_OVERRIDE);
                        capng_apply(CAPNG_EFFECTIVE);
 #endif /* HAVE_CAP_NG_H */
+#ifdef __FreeBSD__
+                       fd = openat(dump_info->dirfd,
+                           dump_info->CurrentFileName,
+                           O_CREAT | O_WRONLY | O_TRUNC, 0644);
+                       if (fd < 0) {
+                               error("unable to open file %s",
+                                   dump_info->CurrentFileName);
+                       }
+                       fp = fdopen(fd, "w");
+                       if (fp == NULL) {
+                               error("unable to fdopen file %s",
+                                   dump_info->CurrentFileName);
+                       }
+                       dump_info->p = pcap_dump_fopen(dump_info->pd, fp);
+#else  /* !__FreeBSD__ */
                        dump_info->p = pcap_dump_open(dump_info->pd, dump_info->CurrentFileName);
+#endif
 #ifdef HAVE_CAP_NG_H
                        capng_update(CAPNG_DROP, CAPNG_EFFECTIVE, CAP_DAC_OVERRIDE);
                        capng_apply(CAPNG_EFFECTIVE);
 #endif /* HAVE_CAP_NG_H */
                        if (dump_info->p == NULL)
                                error("%s", pcap_geterr(pd));
+#ifdef __FreeBSD__
+                       cap_rights_init(&rights, CAP_SEEK, CAP_WRITE);
+                       if (cap_rights_limit(fileno(pcap_dump_file(dump_info->p)),
+                           &rights) < 0 && errno != ENOSYS) {
+                               error("unable to limit dump descriptor");
+                       }
+#endif
                }
        }
 
@@ -1870,6 +1977,11 @@ dump_packet_and_trunc(u_char *user, const struct pcap_pkthdr *h, const u_char *s
         * file could put it over Cflag.
         */
        if (Cflag != 0 && pcap_dump_ftell(dump_info->p) > Cflag) {
+#ifdef __FreeBSD__
+               FILE *fp;
+               int fd;
+#endif
+
                /*
                 * Close the current file and open a new one.
                 */
@@ -1892,9 +2004,31 @@ dump_packet_and_trunc(u_char *user, const struct pcap_pkthdr *h, const u_char *s
                if (dump_info->CurrentFileName == NULL)
                        error("dump_packet_and_trunc: malloc");
                MakeFilename(dump_info->CurrentFileName, dump_info->WFileName, Cflag_count, WflagChars);
+#ifdef __FreeBSD__
+               fd = openat(dump_info->dirfd, dump_info->CurrentFileName,
+                   O_CREAT | O_WRONLY | O_TRUNC, 0644);
+               if (fd < 0) {
+                       error("unable to open file %s",
+                           dump_info->CurrentFileName);
+               }
+               fp = fdopen(fd, "w");
+               if (fp == NULL) {
+                       error("unable to fdopen file %s",
+                           dump_info->CurrentFileName);
+               }
+               dump_info->p = pcap_dump_fopen(dump_info->pd, fp);
+#else  /* !__FreeBSD__ */
                dump_info->p = pcap_dump_open(dump_info->pd, dump_info->CurrentFileName);
+#endif
                if (dump_info->p == NULL)
                        error("%s", pcap_geterr(pd));
+#ifdef __FreeBSD__
+               cap_rights_init(&rights, CAP_SEEK, CAP_WRITE);
+               if (cap_rights_limit(fileno(pcap_dump_file(dump_info->p)),
+                   &rights) < 0 && errno != ENOSYS) {
+                       error("unable to limit dump descriptor");
+               }
+#endif
        }
 
        pcap_dump((u_char *)dump_info->p, h, sp);
_______________________________________________
tcpdump-workers mailing list
tcpdump-workers () lists tcpdump org
https://lists.sandelman.ca/mailman/listinfo/tcpdump-workers


Current thread: