Permalink
Browse files

Add support for FreeBSD capsicum sandboxing.

1 parent 572d634 commit c8275aaf91cdb3a949d4808f0b64236c8c752b72 Loganaden Velvindron committed with guyharris Jul 10, 2014
Showing with 219 additions and 1 deletion.
  1. +1 −0 CREDITS
  2. +18 −0 config.h.in
  3. +44 −0 configure
  4. +21 −0 configure.in
  5. +135 −1 tcpdump.c
View
@@ -116,6 +116,7 @@ Additional people who have contributed patches:
Krzysztof Halasa <khc at pm dot waw dot pl>
Larry Lile <lile at stdio dot com>
Lennert Buytenhek <buytenh at gnu dot org>
+ Loganaden Velvindron <logan at elandsys dot com>
Longinus00 <Longinus00 at gmail dot com>
Loris Degioanni <loris at netgroup-serv dot polito dot it>
Love Hörnquist-Åstrand <lha at stacken dot kth dot se>
View
@@ -9,6 +9,21 @@
/* Define to 1 if you have the `bpf_dump' function. */
#undef HAVE_BPF_DUMP
+/* capsicum support available */
+#undef HAVE_CAPSICUM
+
+/* Define to 1 if you have the `cap_enter' function. */
+#undef HAVE_CAP_ENTER
+
+/* Define to 1 if you have the `cap_ioctls_limit' function. */
+#undef HAVE_CAP_IOCTLS_LIMIT
+
+/* Define to 1 if you have the `cap_rights_init' function. */
+#undef HAVE_CAP_RIGHTS_INIT
+
+/* Define to 1 if you have the `cap_rights_limit' function. */
+#undef HAVE_CAP_RIGHTS_LIMIT
+
/* Define to 1 if you have the declaration of `ether_ntohost', and to 0 if you
don't. */
#undef HAVE_DECL_ETHER_NTOHOST
@@ -67,6 +82,9 @@
/* Define to 1 if you have the <net/pfvar.h> header file. */
#undef HAVE_NET_PFVAR_H
+/* Define to 1 if you have the `openat' function. */
+#undef HAVE_OPENAT
+
/* Define to 1 if you have the <openssl/evp.h> header file. */
#undef HAVE_OPENSSL_EVP_H
View
@@ -703,6 +703,7 @@ with_smi
enable_smb
with_user
with_chroot
+with_sandbox_capsicum
enable_ipv6
with_crypto
'
@@ -1340,6 +1341,7 @@ Optional Packages:
--without-smi don't link with libsmi
--with-user=USERNAME drop privileges by default to USERNAME
--with-chroot=DIRECTORY when dropping privileges, chroot to DIRECTORY
+ --with-sandbox-capsicum
--with-crypto use OpenSSL libcrypto [default=yes, if available]
Some influential environment variables:
@@ -4516,6 +4518,48 @@ else
$as_echo "no" >&6; }
fi
+
+# Check whether --with-sandbox-capsicum was given.
+if test "${with_sandbox_capsicum+set}" = set; then :
+ withval=$with_sandbox_capsicum;
+fi
+
+#
+# Check whether various functions are available. If any are, set
+# ac_lbl_capsicum_function_seen to yes; if any are not, set
+# ac_lbl_capsicum_function_not_seen to yes.
+#
+# All of them must be available in order to enable capsicum sandboxing.
+#
+if test ! -z "$with_sandbox-capsicum" && test "$with_sandbox-capsicum" != "no" ; then
+ for ac_func in cap_enter cap_rights_init cap_rights_limit cap_ioctls_limit openat
+do :
+ as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
+ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
+if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
+ cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+ ac_lbl_capsicum_function_seen=yes
+else
+ ac_lbl_capsicum_function_not_seen=yes
+fi
+done
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to sandbox using capsicum" >&5
+$as_echo_n "checking whether to sandbox using capsicum... " >&6; }
+if test "x$ac_lbl_capsicum_function_seen" = "xyes" -a "x$ac_lbl_capsicum_function_not_seen" != "xyes"; then
+
+$as_echo "#define HAVE_CAPSICUM 1" >>confdefs.h
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
#
# We must check this before checking whether to enable IPv6, because,
# on some platforms (such as SunOS 5.x), the test program requires
View
@@ -177,6 +177,27 @@ else
AC_MSG_RESULT(no)
fi
+AC_ARG_WITH(sandbox-capsicum, [ --with-sandbox-capsicum ])
+#
+# Check whether various functions are available. If any are, set
+# ac_lbl_capsicum_function_seen to yes; if any are not, set
+# ac_lbl_capsicum_function_not_seen to yes.
+#
+# All of them must be available in order to enable capsicum sandboxing.
+#
+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_lbl_capsicum_function_seen=yes,
+ ac_lbl_capsicum_function_not_seen=yes)
+fi
+AC_MSG_CHECKING([whether to sandbox using capsicum])
+if test "x$ac_lbl_capsicum_function_seen" = "xyes" -a "x$ac_lbl_capsicum_function_not_seen" != "xyes"; then
+ 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
View
@@ -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);

0 comments on commit c8275aa

Please sign in to comment.