]> The Tcpdump Group git mirrors - libpcap/commitdiff
Set more function pointers for "dead" pcap_t's.
authorGuy Harris <[email protected]>
Thu, 22 Mar 2018 19:20:28 +0000 (12:20 -0700)
committerGuy Harris <[email protected]>
Thu, 22 Mar 2018 19:20:28 +0000 (12:20 -0700)
That way, pcap APIs will return errors on a "dead" pcap_t rather than
crashing by dereferencing a null function pointer.

This is a better fix for the issue in GitHub pull request #683.

pcap.c

diff --git a/pcap.c b/pcap.c
index ca4511d088687e18bd2688e1ff01623ad2f2f163..c5afa520d125a251a89f0767378994682f1d9828 100644 (file)
--- a/pcap.c
+++ b/pcap.c
@@ -3331,14 +3331,6 @@ pcap_stats(pcap_t *p, struct pcap_stat *ps)
        return (p->stats_op(p, ps));
 }
 
-static int
-pcap_stats_dead(pcap_t *p, struct pcap_stat *ps _U_)
-{
-       pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
-           "Statistics aren't available from a pcap_open_dead pcap_t");
-       return (-1);
-}
-
 #ifdef _WIN32
 struct pcap_stat *
 pcap_stats_ex(pcap_t *p, int *pcap_stat_size)
@@ -3352,86 +3344,36 @@ pcap_setbuff(pcap_t *p, int dim)
        return (p->setbuff_op(p, dim));
 }
 
-static int
-pcap_setbuff_dead(pcap_t *p, int dim)
-{
-       pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
-           "The kernel buffer size cannot be set on a pcap_open_dead pcap_t");
-       return (-1);
-}
-
 int
 pcap_setmode(pcap_t *p, int mode)
 {
        return (p->setmode_op(p, mode));
 }
 
-static int
-pcap_setmode_dead(pcap_t *p, int mode)
-{
-       pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
-           "impossible to set mode on a pcap_open_dead pcap_t");
-       return (-1);
-}
-
 int
 pcap_setmintocopy(pcap_t *p, int size)
 {
        return (p->setmintocopy_op(p, size));
 }
 
-static int
-pcap_setmintocopy_dead(pcap_t *p, int size)
-{
-       pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
-           "The mintocopy parameter cannot be set on a pcap_open_dead pcap_t");
-       return (-1);
-}
-
 HANDLE
 pcap_getevent(pcap_t *p)
 {
        return (p->getevent_op(p));
 }
 
-static HANDLE
-pcap_getevent_dead(pcap_t *p)
-{
-       pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
-           "A pcap_open_dead pcap_t has no event handle");
-       return (INVALID_HANDLE_VALUE);
-}
-
 int
 pcap_oid_get_request(pcap_t *p, bpf_u_int32 oid, void *data, size_t *lenp)
 {
        return (p->oid_get_request_op(p, oid, data, lenp));
 }
 
-static int
-pcap_oid_get_request_dead(pcap_t *p, bpf_u_int32 oid _U_, void *data _U_,
-    size_t *lenp _U_)
-{
-       pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
-           "An OID get request cannot be performed on a pcap_open_dead pcap_t");
-       return (PCAP_ERROR);
-}
-
 int
 pcap_oid_set_request(pcap_t *p, bpf_u_int32 oid, const void *data, size_t *lenp)
 {
        return (p->oid_set_request_op(p, oid, data, lenp));
 }
 
-static int
-pcap_oid_set_request_dead(pcap_t *p, bpf_u_int32 oid _U_, const void *data _U_,
-    size_t *lenp _U_)
-{
-       pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
-           "An OID set request cannot be performed on a pcap_open_dead pcap_t");
-       return (PCAP_ERROR);
-}
-
 pcap_send_queue *
 pcap_sendqueue_alloc(u_int memsize)
 {
@@ -3487,56 +3429,24 @@ pcap_sendqueue_transmit(pcap_t *p, pcap_send_queue *queue, int sync)
        return (p->sendqueue_transmit_op(p, queue, sync));
 }
 
-static u_int
-pcap_sendqueue_transmit_dead(pcap_t *p, pcap_send_queue *queue, int sync)
-{
-       pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
-           "Packets cannot be transmitted on a pcap_open_dead pcap_t");
-       return (0);
-}
-
 int
 pcap_setuserbuffer(pcap_t *p, int size)
 {
        return (p->setuserbuffer_op(p, size));
 }
 
-static int
-pcap_setuserbuffer_dead(pcap_t *p, int size)
-{
-       pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
-           "The user buffer cannot be set on a pcap_open_dead pcap_t");
-       return (-1);
-}
-
 int
 pcap_live_dump(pcap_t *p, char *filename, int maxsize, int maxpacks)
 {
        return (p->live_dump_op(p, filename, maxsize, maxpacks));
 }
 
-static int
-pcap_live_dump_dead(pcap_t *p, char *filename, int maxsize, int maxpacks)
-{
-       pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
-           "Live packet dumping cannot be performed on a pcap_open_dead pcap_t");
-       return (-1);
-}
-
 int
 pcap_live_dump_ended(pcap_t *p, int sync)
 {
        return (p->live_dump_ended_op(p, sync));
 }
 
-static int
-pcap_live_dump_ended_dead(pcap_t *p, int sync)
-{
-       pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
-           "Live packet dumping cannot be performed on a pcap_open_dead pcap_t");
-       return (-1);
-}
-
 PAirpcapHandle
 pcap_get_airpcap_handle(pcap_t *p)
 {
@@ -3549,12 +3459,6 @@ pcap_get_airpcap_handle(pcap_t *p)
        }
        return (handle);
 }
-
-static PAirpcapHandle
-pcap_get_airpcap_handle_dead(pcap_t *p)
-{
-       return (NULL);
-}
 #endif
 
 /*
@@ -3677,6 +3581,220 @@ pcap_cleanup_live_common(pcap_t *p)
 #endif
 }
 
+/*
+ * API compatible with WinPcap's "send a packet" routine - returns -1
+ * on error, 0 otherwise.
+ *
+ * XXX - what if we get a short write?
+ */
+int
+pcap_sendpacket(pcap_t *p, const u_char *buf, int size)
+{
+       if (p->inject_op(p, buf, size) == -1)
+               return (-1);
+       return (0);
+}
+
+/*
+ * API compatible with OpenBSD's "send a packet" routine - returns -1 on
+ * error, number of bytes written otherwise.
+ */
+int
+pcap_inject(pcap_t *p, const void *buf, size_t size)
+{
+       return (p->inject_op(p, buf, size));
+}
+
+void
+pcap_close(pcap_t *p)
+{
+       if (p->opt.device != NULL)
+               free(p->opt.device);
+       p->cleanup_op(p);
+       free(p);
+}
+
+/*
+ * Given a BPF program, a pcap_pkthdr structure for a packet, and the raw
+ * data for the packet, check whether the packet passes the filter.
+ * Returns the return value of the filter program, which will be zero if
+ * the packet doesn't pass and non-zero if the packet does pass.
+ */
+int
+pcap_offline_filter(const struct bpf_program *fp, const struct pcap_pkthdr *h,
+    const u_char *pkt)
+{
+       const struct bpf_insn *fcode = fp->bf_insns;
+
+       if (fcode != NULL)
+               return (bpf_filter(fcode, pkt, h->len, h->caplen));
+       else
+               return (0);
+}
+
+static int
+pcap_read_dead(pcap_t *p, int cnt _U_, pcap_handler callback _U_,
+    u_char *user _U_)
+{
+       pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+           "Packets aren't available from a pcap_open_dead pcap_t");
+       return (-1);
+}
+
+static int
+pcap_inject_dead(pcap_t *p, const void *buf _U_, size_t size _U_)
+{
+       pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+           "Packets can't be sent on a pcap_open_dead pcap_t");
+       return (-1);
+}
+
+static int
+pcap_setfilter_dead(pcap_t *p, struct bpf_program *fp _U_)
+{
+       pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+           "A filter cannot be set on a pcap_open_dead pcap_t");
+       return (-1);
+}
+
+static int
+pcap_setdirection_dead(pcap_t *p, pcap_direction_t d _U_)
+{
+       pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+           "The packet direction cannot be set on a pcap_open_dead pcap_t");
+       return (-1);
+}
+
+static int
+pcap_set_datalink_dead(pcap_t *p, int dlt _U_)
+{
+       pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+           "The link-layer header type cannot be set on a pcap_open_dead pcap_t");
+       return (-1);
+}
+
+static int
+pcap_getnonblock_dead(pcap_t *p)
+{
+       pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+           "A pcap_open_dead pcap_t does not have a non-blocking mode setting");
+       return (-1);
+}
+
+static int
+pcap_setnonblock_dead(pcap_t *p, int nonblock _U_)
+{
+       pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+           "A pcap_open_dead pcap_t does not have a non-blocking mode setting");
+       return (-1);
+}
+
+static int
+pcap_stats_dead(pcap_t *p, struct pcap_stat *ps _U_)
+{
+       pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+           "Statistics aren't available from a pcap_open_dead pcap_t");
+       return (-1);
+}
+
+#ifdef _WIN32
+struct pcap_stat *
+pcap_stats_ex_dead(pcap_t *p, int *pcap_stat_size _U_)
+{
+       pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+           "Statistics aren't available from a pcap_open_dead pcap_t");
+       return (NULL);
+}
+
+static int
+pcap_setbuff_dead(pcap_t *p, int dim)
+{
+       pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+           "The kernel buffer size cannot be set on a pcap_open_dead pcap_t");
+       return (-1);
+}
+
+static int
+pcap_setmode_dead(pcap_t *p, int mode)
+{
+       pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+           "impossible to set mode on a pcap_open_dead pcap_t");
+       return (-1);
+}
+
+static int
+pcap_setmintocopy_dead(pcap_t *p, int size)
+{
+       pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+           "The mintocopy parameter cannot be set on a pcap_open_dead pcap_t");
+       return (-1);
+}
+
+static HANDLE
+pcap_getevent_dead(pcap_t *p)
+{
+       pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+           "A pcap_open_dead pcap_t has no event handle");
+       return (INVALID_HANDLE_VALUE);
+}
+
+static int
+pcap_oid_get_request_dead(pcap_t *p, bpf_u_int32 oid _U_, void *data _U_,
+    size_t *lenp _U_)
+{
+       pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+           "An OID get request cannot be performed on a pcap_open_dead pcap_t");
+       return (PCAP_ERROR);
+}
+
+static int
+pcap_oid_set_request_dead(pcap_t *p, bpf_u_int32 oid _U_, const void *data _U_,
+    size_t *lenp _U_)
+{
+       pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+           "An OID set request cannot be performed on a pcap_open_dead pcap_t");
+       return (PCAP_ERROR);
+}
+
+static u_int
+pcap_sendqueue_transmit_dead(pcap_t *p, pcap_send_queue *queue, int sync)
+{
+       pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+           "Packets cannot be transmitted on a pcap_open_dead pcap_t");
+       return (0);
+}
+
+static int
+pcap_setuserbuffer_dead(pcap_t *p, int size)
+{
+       pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+           "The user buffer cannot be set on a pcap_open_dead pcap_t");
+       return (-1);
+}
+
+static int
+pcap_live_dump_dead(pcap_t *p, char *filename, int maxsize, int maxpacks)
+{
+       pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+           "Live packet dumping cannot be performed on a pcap_open_dead pcap_t");
+       return (-1);
+}
+
+static int
+pcap_live_dump_ended_dead(pcap_t *p, int sync)
+{
+       pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+           "Live packet dumping cannot be performed on a pcap_open_dead pcap_t");
+       return (-1);
+}
+
+static PAirpcapHandle
+pcap_get_airpcap_handle_dead(pcap_t *p)
+{
+       return (NULL);
+}
+#endif /* _WIN32 */
+
 static void
 pcap_cleanup_dead(pcap_t *p _U_)
 {
@@ -3695,7 +3813,14 @@ pcap_open_dead_with_tstamp_precision(int linktype, int snaplen, u_int precision)
                break;
 
        default:
-               return NULL;
+               /*
+                * This doesn't really matter, but we don't have any way
+                * to report particular errors, so the only failure we
+                * should have is a memory allocation failure.  Just
+                * pick microsecond precision.
+                */
+               precision = PCAP_TSTAMP_PRECISION_MICRO;
+               break;
        }
        p = malloc(sizeof(*p));
        if (p == NULL)
@@ -3704,9 +3829,16 @@ pcap_open_dead_with_tstamp_precision(int linktype, int snaplen, u_int precision)
        p->snapshot = snaplen;
        p->linktype = linktype;
        p->opt.tstamp_precision = precision;
+       p->read_op = pcap_read_dead;
+       p->inject_op = pcap_inject_dead;
+       p->setfilter_op = pcap_setfilter_dead;
+       p->setdirection_op = pcap_setdirection_dead;
+       p->set_datalink_op = pcap_set_datalink_dead;
+       p->getnonblock_op = pcap_getnonblock_dead;
+       p->setnonblock_op = pcap_setnonblock_dead;
        p->stats_op = pcap_stats_dead;
 #ifdef _WIN32
-       p->stats_ex_op = (stats_ex_op_t)pcap_not_initialized_ptr;
+       p->stats_ex_op = pcap_stats_ex_dead;
        p->setbuff_op = pcap_setbuff_dead;
        p->setmode_op = pcap_setmode_dead;
        p->setmintocopy_op = pcap_setmintocopy_dead;
@@ -3737,57 +3869,6 @@ pcap_open_dead(int linktype, int snaplen)
            PCAP_TSTAMP_PRECISION_MICRO));
 }
 
-/*
- * API compatible with WinPcap's "send a packet" routine - returns -1
- * on error, 0 otherwise.
- *
- * XXX - what if we get a short write?
- */
-int
-pcap_sendpacket(pcap_t *p, const u_char *buf, int size)
-{
-       if (p->inject_op(p, buf, size) == -1)
-               return (-1);
-       return (0);
-}
-
-/*
- * API compatible with OpenBSD's "send a packet" routine - returns -1 on
- * error, number of bytes written otherwise.
- */
-int
-pcap_inject(pcap_t *p, const void *buf, size_t size)
-{
-       return (p->inject_op(p, buf, size));
-}
-
-void
-pcap_close(pcap_t *p)
-{
-       if (p->opt.device != NULL)
-               free(p->opt.device);
-       p->cleanup_op(p);
-       free(p);
-}
-
-/*
- * Given a BPF program, a pcap_pkthdr structure for a packet, and the raw
- * data for the packet, check whether the packet passes the filter.
- * Returns the return value of the filter program, which will be zero if
- * the packet doesn't pass and non-zero if the packet does pass.
- */
-int
-pcap_offline_filter(const struct bpf_program *fp, const struct pcap_pkthdr *h,
-    const u_char *pkt)
-{
-       const struct bpf_insn *fcode = fp->bf_insns;
-
-       if (fcode != NULL)
-               return (bpf_filter(fcode, pkt, h->len, h->caplen));
-       else
-               return (0);
-}
-
 #ifdef YYDEBUG
 /*
  * Set the internal "debug printout" flag for the filter expression parser.