tcpdump mailing list archives

Re: FreeBSD sandboxing support via capsicum


From: Loganaden Velvindron <logan () elandsys com>
Date: Wed, 9 Jul 2014 05:14:15 -0700

On Sat, Jul 05, 2014 at 01:34:15PM -0700, Guy Harris wrote:

On Jul 5, 2014, at 1:15 PM, Loganaden Velvindron <logan () elandsys com> wrote:

FreeBSD has designed capsicum which is a sandboxing mechanism.

Please find below a patch against FreeBSD 10 Release:

So this will compile on all versions of FreeBSD, correct?

If not, please update the configure script to test for the relevant APIs, and enable the new code only on systems 
with those APIs.

Thank you for your feeeback.

Updated diff. Feedback welcomed.

diff --git a/configure.in b/configure.in
index c88f470..8488653 100644
--- a/configure.in
+++ b/configure.in
@@ -177,6 +177,16 @@ else
        AC_MSG_RESULT(no)
 fi
 
+AC_ARG_WITH(sandbox-capsicum, [ --with-sandbox-capsicum ])
+AC_MSG_CHECKING([whether to sandbox using capsicum])
+if test ! -z "$with_sandbox-capsicum" && test "$with_sandbox-capsicum" != "no" ; then
+       AC_CHECK_FUNCS(cap_enter cap_rights_init cap_rights_limit cap_ioctls_limit openat,
+               AC_DEFINE(HAVE_CAPSICUM, 1, [capsicum support available]))
+       AC_MSG_RESULT(yes)
+else
+       AC_MSG_RESULT(no)
+fi
+
 #
 # We must check this before checking whether to enable IPv6, because,
 # on some platforms (such as SunOS 5.x), the test program requires
diff --git a/tcpdump.c b/tcpdump.c
index 7db319a..40b930d 100644
--- a/tcpdump.c
+++ b/tcpdump.c
@@ -72,6 +72,13 @@ extern int SIZE_BUF;
 #include <stdlib.h>
 #include <string.h>
 #include <limits.h>
+#ifdef HAVE_CAPSICUM
+#include <sys/capability.h>
+#include <sys/ioccom.h>
+#include <net/bpf.h>
+#include <fcntl.h>
+#include <libgen.h>
+#endif /* HAVE_CAPSICUM */
 #ifndef WIN32
 #include <sys/wait.h>
 #include <sys/resource.h>
@@ -441,6 +448,9 @@ struct dump_info {
        char    *CurrentFileName;
        pcap_t  *pd;
        pcap_dumper_t *p;
+#ifdef HAVE_CAPSICUM
+       int     dirfd;
+#endif
 };
 
 #ifdef HAVE_PCAP_SET_TSTAMP_TYPE
@@ -910,6 +920,11 @@ main(int argc, char **argv)
 #endif
        int status;
        FILE *VFile;
+#ifdef HAVE_CAPSICUM
+       cap_rights_t rights;
+       int cansandbox;
+#endif /* HAVE_CAPSICUM */
+
 #ifdef WIN32
        if(wsockinit() != 0) return 1;
 #endif /* WIN32 */
@@ -1423,6 +1438,13 @@ main(int argc, char **argv)
 
                if (pd == NULL)
                        error("%s", ebuf);
+#ifdef HAVE_CAPSICUM
+               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) {
@@ -1687,6 +1709,21 @@ main(int argc, char **argv)
 
        if (pcap_setfilter(pd, &fcode) < 0)
                error("%s", pcap_geterr(pd));
+#ifdef HAVE_CAPSICUM
+       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. */
@@ -1708,9 +1745,32 @@ main(int argc, char **argv)
 #endif
                if (p == NULL)
                        error("%s", pcap_geterr(pd));
+#ifdef HAVE_CAPSICUM
+               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 HAVE_CAPSICUM
+                       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  /* !HAVE_CAPSICUM */
                        dumpinfo.WFileName = WFileName;
+#endif
+                       callback = dump_packet_and_trunc;
                        dumpinfo.pd = pd;
                        dumpinfo.p = p;
                        pcap_userdata = (u_char *)&dumpinfo;
@@ -1780,6 +1840,15 @@ main(int argc, char **argv)
                (void)fflush(stderr);
        }
 #endif /* WIN32 */
+
+#ifdef HAVE_CAPSICUM
+       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 /* HAVE_CAPSICUM */
+
        do {
                status = pcap_loop(pd, cnt, callback, pcap_userdata);
                if (WFileName == NULL) {
@@ -1827,6 +1896,13 @@ main(int argc, char **argv)
                                pd = pcap_open_offline(RFileName, ebuf);
                                if (pd == NULL)
                                        error("%s", ebuf);
+#ifdef HAVE_CAPSICUM
+                               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);
@@ -1995,6 +2071,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 HAVE_CAPSICUM
+       cap_rights_t rights;
+#endif
 
        ++packets_captured;
 
@@ -2023,6 +2102,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 HAVE_CAPSICUM
+                       FILE *fp;
+                       int fd;
+#endif
+
                        /* Update the Gflag_time */
                        Gflag_time = t;
                        /* Update Gflag_count */
@@ -2076,13 +2160,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 HAVE_CAPSICUM
+                       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  /* !HAVE_CAPSICUM */
                        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 HAVE_CAPSICUM
+                       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
                }
        }
 
@@ -2092,6 +2199,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 HAVE_CAPSICUM
+               FILE *fp;
+               int fd;
+#endif
+
                /*
                 * Close the current file and open a new one.
                 */
@@ -2114,9 +2226,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 HAVE_CAPSICUM
+               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  /* !HAVE_CAPSICUM */
                dump_info->p = pcap_dump_open(dump_info->pd, dump_info->CurrentFileName);
+#endif
                if (dump_info->p == NULL)
                        error("%s", pcap_geterr(pd));
+#ifdef HAVE_CAPSICUM
+               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: