From owner-svn-src-head@FreeBSD.ORG Sun Jul 7 21:19:54 2013 Return-Path: Delivered-To: svn-src-head@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115]) by hub.freebsd.org (Postfix) with ESMTP id 341C4529; Sun, 7 Jul 2013 21:19:54 +0000 (UTC) (envelope-from pjd@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) by mx1.freebsd.org (Postfix) with ESMTP id 14F05170C; Sun, 7 Jul 2013 21:19:54 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.7/8.14.7) with ESMTP id r67LJru0040766; Sun, 7 Jul 2013 21:19:53 GMT (envelope-from pjd@svn.freebsd.org) Received: (from pjd@localhost) by svn.freebsd.org (8.14.7/8.14.5/Submit) id r67LJrBS040765; Sun, 7 Jul 2013 21:19:53 GMT (envelope-from pjd@svn.freebsd.org) Message-Id: <201307072119.r67LJrBS040765@svn.freebsd.org> From: Pawel Jakub Dawidek Date: Sun, 7 Jul 2013 21:19:53 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r253004 - head/contrib/tcpdump X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 07 Jul 2013 21:19:54 -0000 Author: pjd Date: Sun Jul 7 21:19:53 2013 New Revision: 253004 URL: http://svnweb.freebsd.org/changeset/base/253004 Log: Sandbox tcpdump(8) using Capsicum's capability mode and capabilities. For now, sandboxing is done only if -n option was specified and neither -z nor -V options were given. Because it is very common to run tcpdump(8) with the -n option for speed, I decided to commit sandboxing now. To also support sandboxing when -n option wasn't specified, we need Casper daemon and its services that are not available in FreeBSD yet. - Limit file descriptors of a file specified by -r option or files specified via -V option to CAP_READ only. - If neither -r nor -V options were specified, we operate on /dev/bpf. Limit its descriptor to CAP_READ and CAP_IOCTL plus limit allowed ioctls to BIOCGSTATS only. - Limit file descriptor of a file specified by -w option to CAP_SEEK and CAP_WRITE. - If either -C or -G options were specified, we open directory containing destination file and we limit directory descriptor to CAP_CREATE, CAP_FCNTL, CAP_FTRUNCATE, CAP_LOOKUP, CAP_SEEK and CAP_WRITE. Newly opened/created files are limited to CAP_SEEK and CAP_WRITE only. - Enter capability mode if -n option was specified and neither -z nor -V options were specified. Approved by: delphij, wxs Sponsored by: The FreeBSD Foundation Modified: head/contrib/tcpdump/tcpdump.c Modified: head/contrib/tcpdump/tcpdump.c ============================================================================== --- head/contrib/tcpdump/tcpdump.c Sun Jul 7 20:44:04 2013 (r253003) +++ head/contrib/tcpdump/tcpdump.c Sun Jul 7 21:19:53 2013 (r253004) @@ -68,6 +68,13 @@ extern int SIZE_BUF; #include #include #include +#ifdef __FreeBSD__ +#include +#include +#include +#include +#include +#endif /* __FreeBSD__ */ #ifndef WIN32 #include #include @@ -384,6 +391,9 @@ struct dump_info { char *CurrentFileName; pcap_t *pd; pcap_dumper_t *p; +#ifdef __FreeBSD__ + int dirfd; +#endif }; #ifdef HAVE_PCAP_SET_TSTAMP_TYPE @@ -702,6 +712,10 @@ main(int argc, char **argv) #endif int status; FILE *VFile; +#ifdef __FreeBSD__ + int cansandbox; +#endif + #ifdef WIN32 if(wsockinit() != 0) return 1; #endif /* WIN32 */ @@ -1189,6 +1203,12 @@ main(int argc, char **argv) pd = pcap_open_offline(RFileName, ebuf); if (pd == NULL) error("%s", ebuf); +#ifdef __FreeBSD__ + if (cap_rights_limit(fileno(pcap_file(pd)), CAP_READ) < 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) { @@ -1437,6 +1457,20 @@ 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 }; + + if (cap_rights_limit(pcap_fileno(pd), + CAP_IOCTL | CAP_READ) < 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. */ @@ -1458,9 +1492,30 @@ main(int argc, char **argv) #endif if (p == NULL) error("%s", pcap_geterr(pd)); +#ifdef __FreeBSD__ + if (cap_rights_limit(fileno(pcap_dump_file(p)), + CAP_SEEK | CAP_WRITE) < 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)); + } + if (cap_rights_limit(dumpinfo.dirfd, CAP_CREATE | + CAP_FCNTL | CAP_FTRUNCATE | CAP_LOOKUP | CAP_SEEK | + CAP_WRITE) < 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; @@ -1530,6 +1585,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 + do { status = pcap_loop(pd, cnt, callback, pcap_userdata); if (WFileName == NULL) { @@ -1569,6 +1633,12 @@ main(int argc, char **argv) pd = pcap_open_offline(RFileName, ebuf); if (pd == NULL) error("%s", ebuf); +#ifdef __FreeBSD__ + if (cap_rights_limit(fileno(pcap_file(pd)), + CAP_READ) < 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); @@ -1765,6 +1835,11 @@ dump_packet_and_trunc(u_char *user, cons /* 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 */ @@ -1811,13 +1886,35 @@ dump_packet_and_trunc(u_char *user, cons 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__ + if (cap_rights_limit(fileno(pcap_dump_file(dump_info->p)), + CAP_SEEK | CAP_WRITE) < 0 && errno != ENOSYS) { + error("unable to limit dump descriptor"); + } +#endif } } @@ -1827,6 +1924,11 @@ dump_packet_and_trunc(u_char *user, cons * 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. */ @@ -1849,9 +1951,30 @@ dump_packet_and_trunc(u_char *user, cons 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__ + if (cap_rights_limit(fileno(pcap_dump_file(dump_info->p)), + CAP_SEEK | CAP_WRITE) < 0 && errno != ENOSYS) { + error("unable to limit dump descriptor"); + } +#endif } pcap_dump((u_char *)dump_info->p, h, sp);