]> The Tcpdump Group git mirrors - tcpdump/blobdiff - tcpdump.c
Handle very large -f files by rejecting them.
[tcpdump] / tcpdump.c
index d5bf09bdef87bcd5d8bcb47c8d1aff5144b6d052..8f27ba2a47fbbf80700df196f679449c10e84f28 100644 (file)
--- a/tcpdump.c
+++ b/tcpdump.c
@@ -108,6 +108,7 @@ The Regents of the University of California.  All rights reserved.\n";
 #endif /* HAVE_CAP_NG_H */
 #endif /* HAVE_LIBCAP_NG */
 
+#include "netdissect-stdinc.h"
 #include "netdissect.h"
 #include "interface.h"
 #include "addrtoname.h"
@@ -130,7 +131,7 @@ The Regents of the University of California.  All rights reserved.\n";
 #endif
 
 static int Bflag;                      /* buffer size */
-static int Cflag;                      /* rotate dump files after this many bytes */
+static long Cflag;                     /* rotate dump files after this many bytes */
 static int Cflag_count;                        /* Keep track of which file number we're writing */
 static int Dflag;                      /* list available devices and exit */
 /*
@@ -157,7 +158,7 @@ static int Jflag;                   /* list available time stamp types */
 static int jflag = -1;                 /* packet time stamp source */
 static int pflag;                      /* don't go promiscuous */
 #ifdef HAVE_PCAP_SETDIRECTION
-int Qflag = -1;                                /* restrict captured packet by send/receive direction */
+static int Qflag = -1;                 /* restrict captured packet by send/receive direction */
 #endif
 static int Uflag;                      /* "unbuffered" output of dump files */
 static int Wflag;                      /* recycle output files after this number of files */
@@ -171,24 +172,18 @@ static int infoprint;
 char *program_name;
 
 /* Forwards */
-static void error(const char *, ...)
-     __attribute__((noreturn))
-#ifdef __ATTRIBUTE___FORMAT_OK
-     __attribute__((format (printf, 1, 2)))
-#endif /* __ATTRIBUTE___FORMAT_OK */
-     ;
-static void warning(const char *, ...)
-#ifdef __ATTRIBUTE___FORMAT_OK
-     __attribute__((format (printf, 1, 2)))
-#endif /* __ATTRIBUTE___FORMAT_OK */
-     ;
-static void exit_tcpdump(int) __attribute__((noreturn));
+static void error(FORMAT_STRING(const char *), ...) NORETURN PRINTFLIKE(1, 2);
+static void warning(FORMAT_STRING(const char *), ...) PRINTFLIKE(1, 2);
+static void exit_tcpdump(int) NORETURN;
 static RETSIGTYPE cleanup(int);
 static RETSIGTYPE child_cleanup(int);
 static void print_version(void);
 static void print_usage(void);
-static void show_tstamp_types_and_exit(const char *device) __attribute__((noreturn));
-static void show_dlts_and_exit(const char *device) __attribute__((noreturn));
+static void show_tstamp_types_and_exit(pcap_t *, const char *device) NORETURN;
+static void show_dlts_and_exit(pcap_t *, const char *device) NORETURN;
+#ifdef HAVE_PCAP_FINDALLDEVS
+static void show_devices_and_exit (void) NORETURN;
+#endif
 
 static void print_packet(u_char *, const struct pcap_pkthdr *, const u_char *);
 static void dump_packet_and_trunc(u_char *, const struct pcap_pkthdr *, const u_char *);
@@ -337,16 +332,16 @@ exit_tcpdump(int status)
 
 #ifdef HAVE_PCAP_SET_TSTAMP_TYPE
 static void
-show_tstamp_types_and_exit(const char *device)
+show_tstamp_types_and_exit(pcap_t *pc, const char *device)
 {
        int n_tstamp_types;
        int *tstamp_types = 0;
        const char *tstamp_type_name;
        int i;
 
-       n_tstamp_types = pcap_list_tstamp_types(pd, &tstamp_types);
+       n_tstamp_types = pcap_list_tstamp_types(pc, &tstamp_types);
        if (n_tstamp_types < 0)
-               error("%s", pcap_geterr(pd));
+               error("%s", pcap_geterr(pc));
 
        if (n_tstamp_types == 0) {
                fprintf(stderr, "Time stamp type cannot be set for %s\n",
@@ -370,15 +365,15 @@ show_tstamp_types_and_exit(const char *device)
 #endif
 
 static void
-show_dlts_and_exit(const char *device)
+show_dlts_and_exit(pcap_t *pc, const char *device)
 {
        int n_dlts, i;
        int *dlts = 0;
        const char *dlt_name;
 
-       n_dlts = pcap_list_datalinks(pd, &dlts);
+       n_dlts = pcap_list_datalinks(pc, &dlts);
        if (n_dlts < 0)
-               error("%s", pcap_geterr(pd));
+               error("%s", pcap_geterr(pc));
        else if (n_dlts == 0 || !dlts)
                error("No data link types.");
 
@@ -455,7 +450,7 @@ show_devices_and_exit (void)
  * OS X tcpdump uses -g to force non--v output for IP to be on one
  * line, making it more "g"repable;
  *
- * OS X tcpdump uses -k tospecify that packet comments in pcap-ng files
+ * OS X tcpdump uses -k to specify that packet comments in pcap-ng files
  * should be printed;
  *
  * OpenBSD tcpdump uses -o to indicate that OS fingerprinting should be done
@@ -613,11 +608,10 @@ droproot(const char *username, const char *chroot_dir)
 #ifdef HAVE_LIBCAP_NG
                {
                        int ret = capng_change_id(pw->pw_uid, pw->pw_gid, CAPNG_NO_FLAG);
-                       if (ret < 0) {
-                               fprintf(stderr, "error : ret %d\n", ret);
-                       } else {
+                       if (ret < 0)
+                               error("capng_change_id(): return %d\n", ret);
+                       else
                                fprintf(stderr, "dropped privs to %s\n", username);
-                       }
                }
 #else
                if (initgroups(pw->pw_name, pw->pw_gid) != 0 ||
@@ -640,12 +634,13 @@ droproot(const char *username, const char *chroot_dir)
                exit_tcpdump(1);
        }
 #ifdef HAVE_LIBCAP_NG
-       /* We don't need CAP_SETUID and CAP_SETGID any more. */
+       /* We don't need CAP_SETUID, CAP_SETGID and CAP_SYS_CHROOT any more. */
        capng_updatev(
                CAPNG_DROP,
                CAPNG_EFFECTIVE | CAPNG_PERMITTED,
                CAP_SETUID,
                CAP_SETGID,
+               CAP_SYS_CHROOT,
                -1);
        capng_apply(CAPNG_SELECT_BOTH);
 #endif /* HAVE_LIBCAP_NG */
@@ -705,13 +700,15 @@ static char *
 get_next_file(FILE *VFile, char *ptr)
 {
        char *ret;
+       size_t len;
 
        ret = fgets(ptr, PATH_MAX, VFile);
        if (!ret)
                return NULL;
 
-       if (ptr[strlen(ptr) - 1] == '\n')
-               ptr[strlen(ptr) - 1] = '\0';
+       len = strlen (ptr);
+       if (len > 0 && ptr[len - 1] == '\n')
+               ptr[len - 1] = '\0';
 
        return ret;
 }
@@ -828,7 +825,7 @@ copy_argv(register char **argv)
        char *src, *dst;
 
        p = argv;
-       if (*p == 0)
+       if (*p == NULL)
                return 0;
 
        while (*p)
@@ -865,15 +862,22 @@ read_infile(char *fname)
 {
        register int i, fd, cc;
        register char *cp;
-       struct stat buf;
+       our_statb buf;
 
        fd = open(fname, O_RDONLY|O_BINARY);
        if (fd < 0)
                error("can't open %s: %s", fname, pcap_strerror(errno));
 
-       if (fstat(fd, &buf) < 0)
+       if (our_fstat(fd, &buf) < 0)
                error("can't stat %s: %s", fname, pcap_strerror(errno));
 
+       /*
+        * Reject files whose size doesn't fit into an int; a filter
+        * *that* large will probably be too big.
+        */
+       if (buf.st_size > INT_MAX)
+               error("%s is too large", fname);
+
        cp = malloc((u_int)buf.st_size + 1);
        if (cp == NULL)
                error("malloc(%d) for %s: %s", (u_int)buf.st_size + 1,
@@ -882,7 +886,8 @@ read_infile(char *fname)
        if (cc < 0)
                error("read %s: %s", fname, pcap_strerror(errno));
        if (cc != buf.st_size)
-               error("short read %s (%d != %d)", fname, cc, (int)buf.st_size);
+               error("short read %s (%d != %d)", fname, (int) cc,
+                   (int)buf.st_size);
 
        close(fd);
        /* replace "# comment" with spaces */
@@ -971,7 +976,7 @@ open_interface(const char *device, netdissect_options *ndo, char *ebuf)
        }
 #ifdef HAVE_PCAP_SET_TSTAMP_TYPE
        if (Jflag)
-               show_tstamp_types_and_exit(device);
+               show_tstamp_types_and_exit(pc, device);
 #endif
 #ifdef HAVE_PCAP_SET_TSTAMP_PRECISION
        status = pcap_set_tstamp_precision(pc, ndo->ndo_tstamp_precision);
@@ -1028,6 +1033,10 @@ open_interface(const char *device, netdissect_options *ndo, char *ebuf)
                if (status < 0)
                        error("%s: Can't set time stamp type: %s",
                              device, pcap_statustostr(status));
+               else if (status > 0)
+                       warning("When trying to set timestamp type '%s' on %s: %s",
+                               pcap_tstamp_type_val_to_name(jflag), device,
+                               pcap_statustostr(status));
        }
 #endif
        status = pcap_activate(pc);
@@ -1042,9 +1051,9 @@ open_interface(const char *device, netdissect_options *ndo, char *ebuf)
                        /*
                         * Return an error for our caller to handle.
                         */
-                       pcap_close(pc);
                        snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s: %s\n(%s)",
                            device, pcap_statustostr(status), cp);
+                       pcap_close(pc);
                        return (NULL);
                } else if (status == PCAP_ERROR_PERM_DENIED && *cp != '\0')
                        error("%s: %s\n(%s)", device,
@@ -1726,7 +1735,7 @@ main(int argc, char **argv)
                        }
 #endif /* !defined(HAVE_PCAP_CREATE) && defined(_WIN32) */
                if (Lflag)
-                       show_dlts_and_exit(device);
+                       show_dlts_and_exit(pd, device);
                if (yflag_dlt >= 0) {
 #ifdef HAVE_PCAP_SET_DATALINK
                        if (pcap_set_datalink(pd, yflag_dlt) < 0)
@@ -1822,6 +1831,13 @@ main(int argc, char **argv)
                                CAP_SETGID,
                                -1);
                }
+               if (chroot_dir) {
+                       capng_update(
+                               CAPNG_ADD,
+                               CAPNG_PERMITTED | CAPNG_EFFECTIVE,
+                               CAP_SYS_CHROOT
+                               );
+               }
 
                if (WFileName) {
                        capng_update(
@@ -1844,7 +1860,12 @@ main(int argc, char **argv)
        if (RFileName == NULL && VFileName == NULL) {
                static const unsigned long cmds[] = { BIOCGSTATS, BIOCROTZBUF };
 
-               cap_rights_init(&rights, CAP_IOCTL, CAP_READ);
+               /*
+                * The various libpcap devices use a combination of
+                * read (bpf), ioctl (bpf, netmap), poll (netmap)
+                * so we add the relevant access rights.
+                */
+               cap_rights_init(&rights, CAP_IOCTL, CAP_READ, CAP_EVENT);
                if (cap_rights_limit(pcap_fileno(pd), &rights) < 0 &&
                    errno != ENOSYS) {
                        error("unable to limit pcap descriptor");
@@ -2319,6 +2340,7 @@ dump_packet_and_trunc(u_char *user, const struct pcap_pkthdr *h, const u_char *s
                        if (Cflag == 0 && Wflag > 0 && Gflag_count >= Wflag) {
                                (void)fprintf(stderr, "Maximum file limit reached: %d\n",
                                    Wflag);
+                               info(1);
                                exit_tcpdump(0);
                                /* NOTREACHED */
                        }
@@ -2587,6 +2609,14 @@ print_version(void)
        smi_version_string = nd_smi_version_string();
        if (smi_version_string != NULL)
                (void)fprintf (stderr, "SMI-library: %s\n", smi_version_string);
+
+#if defined(__SANITIZE_ADDRESS__)
+       (void)fprintf (stderr, "Compiled with AddressSanitizer/GCC.\n");
+#elif defined(__has_feature)
+#  if __has_feature(address_sanitizer)
+       (void)fprintf (stderr, "Compiled with AddressSanitizer/CLang.\n");
+#  endif
+#endif /* __SANITIZE_ADDRESS__ or __has_feature */
 }
 USES_APPLE_RST