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
This commit is contained in:
parent
c7a08860c7
commit
c7afd8bc1c
@ -68,6 +68,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>
|
||||
@ -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, 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 */
|
||||
@ -1811,13 +1886,35 @@ 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__
|
||||
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, 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.
|
||||
*/
|
||||
@ -1849,9 +1951,30 @@ 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__
|
||||
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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user