[tcpdump-workers] FreeBSD sandboxing support via capsicum
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 p...@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 #include #include +#ifdef __FreeBSD__ +#include +#include +#include +#include +#include +#endif /* __FreeBSD__ */ #ifndef WIN32 #include #include @@ -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__ +
Re: [tcpdump-workers] FreeBSD sandboxing support via capsicum
On Sat, Jul 05, 2014 at 01:34:15PM -0700, Guy Harris wrote: > > On Jul 5, 2014, at 1:15 PM, Loganaden Velvindron 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 #include #include +#ifdef HAVE_CAPSICUM +#include +#include +#include +#include +#include +#endif /* HAVE_CAPSICUM */ #ifndef WIN32 #include #include @@ -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, &r
Re: [tcpdump-workers] FreeBSD sandboxing support via capsicum
On Thu, Jul 10, 2014 at 12:22:28PM -0700, Guy Harris wrote: > > On Jul 9, 2014, at 5:14 AM, Loganaden Velvindron wrote: > > > On Sat, Jul 05, 2014 at 01:34:15PM -0700, Guy Harris wrote: > >> > >> On Jul 5, 2014, at 1:15 PM, Loganaden Velvindron > >> 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. > > Checked in (with some fixes to the configure script - there shouldn't be > anything between AC_MSG_CHECKING and AC_MSG_RESULT that would print any > output, and capsicum should be enabled only if none of the functions were not > found). Thanks. I'll test it. Please note that the code is adapted from code written by Pawel J Dawidek (p...@freebsd.org), and that I simply rewrote it for tcpdump. I think that he also deserves credit in the CREDITS file. > > Michael, should this go into 4.6 or should we wait for the next tcpdump > release? ___ tcpdump-workers mailing list tcpdump-workers@lists.tcpdump.org https://lists.sandelman.ca/mailman/listinfo/tcpdump-workers
[tcpdump-workers] Fix FreeBSD capsicum build on FreeBSD 10.1
Hi guys, Support for FreeBSD capsicum doesn't work on FreeBSD 10.1, due to cap_rights_init which returns a struct, instead of an int. I think that we should follow OpenSSH and not test cap_rights_init. Would it also be possible to add this to the next 4.6.x release as a bugfix ? Kind regards, //Logan C-x-C-c Below is a proposed diff: diff --git a/configure.in b/configure.in index d0e90dd..ecfee64 100644 --- a/configure.in +++ b/configure.in @@ -208,7 +208,7 @@ AC_ARG_WITH(sandbox-capsicum, # 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_CHECK_FUNCS(cap_enter cap_rights_limit cap_ioctls_limit openat, ac_lbl_capsicum_function_seen=yes, ac_lbl_capsicum_function_not_seen=yes) fi ___ tcpdump-workers mailing list tcpdump-workers@lists.tcpdump.org https://lists.sandelman.ca/mailman/listinfo/tcpdump-workers
Re: [tcpdump-workers] Fix FreeBSD capsicum build on FreeBSD 10.1
On Sat, Dec 06, 2014 at 12:40:57PM -0800, Guy Harris wrote: > > On Dec 6, 2014, at 6:51 AM, Loganaden Velvindron wrote: > > > Support for FreeBSD capsicum doesn't work on FreeBSD 10.1, due to > > cap_rights_init which returns a struct, instead of an int. > > Did its return value change in FreeBSD 10? (Presumably it didn't change > between 10 and 10.1.) > No it didn't. > > I think that we should follow OpenSSH and not test cap_rights_init. > > If there are no systems that offer Capsicum but that don't have > cap_rights_init(), there's no need to check for it. Agreed. > > The comment there is > > # > # 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. > # > > but, if there aren't any systems that have some but not all, testing for all > of them is overkill. > > However, AC_CHECK_FUNCS is intended not to care what type a function returns > - unless a header is included that declares a function, it gets declared > within the test program as returning char, so the compiler shouldn't choke on > returning its value from main(). Is this failing due to the *linker* > rejecting it because of mismatched function signatures? > Here's the config.log output: configure:4540: checking for cap_rights_init configure:4540: cc -o conftest -g -O2 conftest.c >&5 /tmp/conftest-942ee0.o: In function `main': /root/tcpdump/tcpdump-4.6.2/conftest.c:66: undefined reference to `cap_rights_in it' cc: error: linker command failed with exit code 1 (use -v to see invocation) configure:4540: $? = 1 configure: failed program was: | /* Define cap_rights_init to an innocuous variant, in case declares cap_rights_init. |For example, HP-UX 11i declares gettimeofday. */ | #define cap_rights_init innocuous_cap_rights_init | | /* System header to define __stub macros and hopefully few prototypes, | which can conflict with char cap_rights_init (); below. | Prefer to if __STDC__ is defined, since | exists even on freestanding compilers. */ | | #ifdef __STDC__ | # include | #else | # include | #endif | | #undef cap_rights_init | /* Override any GCC internal prototype to avoid an error. |Use char because int might match the return type of a GCC |builtin and then its argument prototype would still apply. */ | #ifdef __cplusplus | extern "C" | #endif | char cap_rights_init (); | /* The GNU C library defines this for functions which it implements | to always fail with ENOSYS. Some functions are actually named | something starting with __ and the normal name is an alias. */ | #if defined __stub_cap_rights_init || defined __stub___cap_rights_init | choke me | #endif | | int | main () | { | return cap_rights_init (); | ; | return 0; | } configure:4540: result: no ___ tcpdump-workers mailing list tcpdump-workers@lists.tcpdump.org https://lists.sandelman.ca/mailman/listinfo/tcpdump-workers
Re: [tcpdump-workers] Fix FreeBSD capsicum build on FreeBSD 10.1
On Sat, Dec 06, 2014 at 11:41:51PM -0800, Guy Harris wrote: > > On Dec 6, 2014, at 9:19 PM, Loganaden Velvindron wrote: > > > Here's the config.log output: > > > > configure:4540: checking for cap_rights_init > > configure:4540: cc -o conftest -g -O2 conftest.c >&5 > > /tmp/conftest-942ee0.o: In function `main': > > /root/tcpdump/tcpdump-4.6.2/conftest.c:66: undefined reference to > > `cap_rights_init' > > cc: error: linker command failed with exit code 1 (use -v to see invocation) > > So, in FreeBSD 10.1, is cap_rights_init() a function in libc, or is it a > macro that calls a function with a different name? The linker seems to be > indicating that it's not present in the standard library. According to the man page, it's part of the standard libc: CAP_RIGHTS_INIT(3) FreeBSD Library Functions Manual CAP_RIGHTS_INIT(3) NAME cap_rights_init, cap_rights_set, cap_rights_clear, cap_rights_is_set, cap_rights_is_valid, cap_rights_merge, cap_rights_remove, cap_rights_contains -- manage cap_rights_t structure LIBRARY Standard C Library (libc, -lc) > > ___ tcpdump-workers mailing list tcpdump-workers@lists.tcpdump.org https://lists.sandelman.ca/mailman/listinfo/tcpdump-workers
Re: [tcpdump-workers] Fix FreeBSD capsicum build on FreeBSD 10.1
On Sun, Dec 07, 2014 at 12:13:09AM -0800, Guy Harris wrote: > > On Dec 6, 2014, at 11:44 PM, Loganaden Velvindron wrote: > > > On Sat, Dec 06, 2014 at 11:41:51PM -0800, Guy Harris wrote: > >> > >> On Dec 6, 2014, at 9:19 PM, Loganaden Velvindron > >> wrote: > >> > >>> Here's the config.log output: > >>> > >>> configure:4540: checking for cap_rights_init > >>> configure:4540: cc -o conftest -g -O2 conftest.c >&5 > >>> /tmp/conftest-942ee0.o: In function `main': > >>> /root/tcpdump/tcpdump-4.6.2/conftest.c:66: undefined reference to > >>> `cap_rights_init' > >>> cc: error: linker command failed with exit code 1 (use -v to see > >>> invocation) > >> > >> So, in FreeBSD 10.1, is cap_rights_init() a function in libc, or is it a > >> macro that calls a function with a different name? The linker seems to be > >> indicating that it's not present in the standard library. > > > > According to the man page, it's part of the standard libc: > > And the answer is B) it's a macro that calls a function with a different > name; from in FreeBSD SVN: > > #define cap_rights_init(...) > \ > __cap_rights_init(CAP_RIGHTS_VERSION, __VA_ARGS__, 0ULL) > cap_rights_t *__cap_rights_init(int version, cap_rights_t *rights, ...); > > The same is true of cap_rights_set, cap_rights_clear, and cap_rights_is_set, > so we can't check *any* of them with AC_CHECK_FUNCS. > > The only one we're checking for is cap_rights_init, though, so removing that > from the list (with a comment explaining why we can't check for it) would > suffice. When I checked using "strings", the function is __cap_rights_init() :-) Here's the diff: index d0e90dd..1620bbb 100644 --- a/configure.in +++ b/configure.in @@ -207,8 +207,10 @@ AC_ARG_WITH(sandbox-capsicum, # # All of them must be available in order to enable capsicum sandboxing. # +# NOTE: cap_rights_init is a macro on FreeBSD, so remove it from the list. + 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_CHECK_FUNCS(cap_enter cap_rights_limit cap_ioctls_limit openat, ac_lbl_capsicum_function_seen=yes, ac_lbl_capsicum_function_not_seen=yes) fi ___ tcpdump-workers mailing list tcpdump-workers@lists.tcpdump.org https://lists.sandelman.ca/mailman/listinfo/tcpdump-workers
Re: [tcpdump-workers] Fix FreeBSD capsicum build on FreeBSD 10.1
On Sun, Dec 07, 2014 at 12:13:09AM -0800, Guy Harris wrote: > > On Dec 6, 2014, at 11:44 PM, Loganaden Velvindron wrote: > > > On Sat, Dec 06, 2014 at 11:41:51PM -0800, Guy Harris wrote: > >> > >> On Dec 6, 2014, at 9:19 PM, Loganaden Velvindron > >> wrote: > >> > >>> Here's the config.log output: > >>> > >>> configure:4540: checking for cap_rights_init > >>> configure:4540: cc -o conftest -g -O2 conftest.c >&5 > >>> /tmp/conftest-942ee0.o: In function `main': > >>> /root/tcpdump/tcpdump-4.6.2/conftest.c:66: undefined reference to > >>> `cap_rights_init' > >>> cc: error: linker command failed with exit code 1 (use -v to see > >>> invocation) > >> > >> So, in FreeBSD 10.1, is cap_rights_init() a function in libc, or is it a > >> macro that calls a function with a different name? The linker seems to be > >> indicating that it's not present in the standard library. > > > > According to the man page, it's part of the standard libc: > > And the answer is B) it's a macro that calls a function with a different > name; from in FreeBSD SVN: > > #define cap_rights_init(...) > \ > __cap_rights_init(CAP_RIGHTS_VERSION, __VA_ARGS__, 0ULL) > cap_rights_t *__cap_rights_init(int version, cap_rights_t *rights, ...); > > The same is true of cap_rights_set, cap_rights_clear, and cap_rights_is_set, > so we can't check *any* of them with AC_CHECK_FUNCS. > > The only one we're checking for is cap_rights_init, though, so removing that > from the list (with a comment explaining why we can't check for it) would > suffice. ping :-) ___ tcpdump-workers mailing list tcpdump-workers@lists.tcpdump.org https://lists.sandelman.ca/mailman/listinfo/tcpdump-workers
Re: [tcpdump-workers] Fix FreeBSD capsicum build on FreeBSD 10.1
On Fri, Dec 19, 2014 at 01:29:00PM -0800, Guy Harris wrote: > > On Dec 7, 2014, at 12:17 AM, Loganaden Velvindron wrote: > > > Here's the diff: > > > > index d0e90dd..1620bbb 100644 > > --- a/configure.in > > +++ b/configure.in > > @@ -207,8 +207,10 @@ AC_ARG_WITH(sandbox-capsicum, > > # > > # All of them must be available in order to enable capsicum sandboxing. > > # > > +# NOTE: cap_rights_init is a macro on FreeBSD, so remove it from the list. > > + > > 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_CHECK_FUNCS(cap_enter cap_rights_limit cap_ioctls_limit openat, > >ac_lbl_capsicum_function_seen=yes, > >ac_lbl_capsicum_function_not_seen=yes) > > fi > > I've checked into the trunk a similar change, but with a more elaborate > comment, and cherry-picked it to the 4.7 branch. Awesome ! Thank you. I was looking into the github repo, but couldn't find the change. Do you have the git commit id for this ? ___ tcpdump-workers mailing list tcpdump-workers@lists.tcpdump.org https://lists.sandelman.ca/mailman/listinfo/tcpdump-workers