Hello,

On Wed, Mar 01, 2017 at 05:50:57AM +0100, Joerg Mayer wrote:
> I'm trying to get libpcap working on macOS.
...
> Trying to understand the problem it looks like accessing struct pcap_md (the
> rpcap specific stuff) is broken on non-win32 platforms (or at least on bpf
> platforms).
> 
> The intended memory layout seems to be:
> 
> struct pcap_t (containing a pointer to priv if it exits)
> priv:
> struct pcap_<platform>
> struct pcap_md (if compiling with HAVE_REMOTE)
> 
> The current implementation seems to
> 
> a) only allocate the memory for pcap_md on win (pcap_create_interface() in
>    pcap-win32.c), thus causing an out of bounds access on other platforms.
> b) the access to pcap_md is calculated as priv + sizeof(struct pcap_win)
>    on all platforms which gets redeclared in pcap-new.c and pcap-rpcap.c
>    for just this purpose. This looks wrong to me but I'm not sure.

OK, I think I managed to fix this one. Please see attached patch.

Now it fails (i.e. it no longer crashes!) with:
jmayer@newegg:~/worktmp/libpcap/build(master)$ dumpcap -i 
rpcap://10.122.4.11/wifi0
Capturing on 'rpcap://10.122.4.11/wifi0'
dumpcap: Invalid capture filter "(null)" for interface 
'rpcap://10.122.4.11/wifi0'.

That string isn't a valid capture filter (not-yet-activated pcap_t passed to 
pcap_compile).
See the User's Guide for a description of the capture filter syntax.

jmayer@newegg:~/worktmp/libpcap/build(master)$ dumpcap -i 
rpcap://10.122.4.11/wifi0 -L
Data link types of interface rpcap://10.122.4.11/wifi0 (use option -y to set):
  DLT -3 (not supported)

Both of which seem to be libpcap problems (or symptoms of the same problem).

Kind regards
   JÖrg
-- 
Joerg Mayer                                           <jma...@loplof.de>
We are stuck with technology when what we really want is just stuff that
works. Some say that should read Microsoft instead of technology.
Fix access to struct pcap_md on non-Windows

Previously it was assumed that pcap_md was at offset pcap_t + pcap_win.
That assumption was only correct on Windows systems.

Signed-off-by: Joerg Mayer <jma...@loplof.de>
---
 pcap-int.h   |  3 +++
 pcap-new.c   |  4 ++--
 pcap-rpcap.c | 20 +++++++++-----------
 pcap.c       | 18 +++++++++++++++---
 4 files changed, 29 insertions(+), 16 deletions(-)

diff --git a/pcap-int.h b/pcap-int.h
index 5c8c129..e74eec8 100644
--- a/pcap-int.h
+++ b/pcap-int.h
@@ -178,6 +178,9 @@ struct pcap {
        int break_loop;         /* flag set to force break from packet-reading 
loop */
 
        void *priv;             /* private data for methods */
+#ifdef HAVE_REMOTE
+       void *priv_md;          /* private data for rpcap */
+#endif
 
        int swapped;
        FILE *rfile;            /* null if live capture, non-null if savefile */
diff --git a/pcap-new.c b/pcap-new.c
index 494e425..816f51d 100644
--- a/pcap-new.c
+++ b/pcap-new.c
@@ -940,7 +940,7 @@ pcap_t *pcap_open(const char *source, int snaplen, int 
flags, int read_timeout,
                }
 
                struct pcap_md *md;                             /* structure 
used when doing a remote live capture */
-               md = (struct pcap_md *) ((u_char*)fp->priv + sizeof(struct 
pcap_win));
+               md = (struct pcap_md *)fp->priv_md;
 
                fp->snapshot = snaplen;
                fp->opt.timeout = read_timeout;
@@ -994,7 +994,7 @@ struct pcap_samp *pcap_setsampling(pcap_t *p)
 {
        struct pcap_md *md;                             /* structure used when 
doing a remote live capture */
 
-       md = (struct pcap_md *) ((u_char*)p->priv + sizeof(struct pcap_win));
+       md = (struct pcap_md *)p->priv_md;
        return &(md->rmt_samp);
 }
 
diff --git a/pcap-rpcap.c b/pcap-rpcap.c
index f5f3fa5..51c07ae 100644
--- a/pcap-rpcap.c
+++ b/pcap-rpcap.c
@@ -216,7 +216,7 @@ static int pcap_read_nocb_remote(pcap_t *p, struct 
pcap_pkthdr **pkt_header, u_c
        struct timeval tv;                      /* maximum time the select() 
can block waiting for data */
        struct pcap_md *md;                     /* structure used when doing a 
remote live capture */
 
-       md = (struct pcap_md *) ((u_char*)p->priv + sizeof(struct pcap_win));
+       md = (struct pcap_md *)p->priv_md;
 
        /*
         * Define the packet buffer timeout, to be used in the select()
@@ -423,7 +423,7 @@ static void pcap_cleanup_remote(pcap_t *fp)
        int active = 0;                                 /* active mode or not? 
*/
        struct pcap_md *md;                             /* structure used when 
doing a remote live capture */
 
-       md = (struct pcap_md *) ((u_char*)fp->priv + sizeof(struct pcap_win));
+       md = (struct pcap_md *)fp->priv_md;
 
        /* detect if we're in active mode */
        temp = activeHosts;
@@ -559,7 +559,7 @@ static struct pcap_stat *rpcap_stats_remote(pcap_t *p, 
struct pcap_stat *ps, int
        int retval;                             /* temp variable which stores 
functions return value */
        struct pcap_md *md;                     /* structure used when doing a 
remote live capture */
 
-       md = (struct pcap_md *) ((u_char*)p->priv + sizeof(struct pcap_win));
+       md = (struct pcap_md *)p->priv_md;
 
        /*
         * If the capture has still to start, we cannot ask statistics to the 
other peer,
@@ -710,8 +710,7 @@ int pcap_opensource_remote(pcap_t *fp, struct pcap_rmtauth 
*auth)
 
        struct pcap_md *md;                     /* structure used when doing a 
remote live capture */
 
-       md = (struct pcap_md *) ((u_char*)fp->priv + sizeof(struct pcap_win));
-
+       md = (struct pcap_md *)fp->priv_md;
 
        /*
         * determine the type of the source (NULL, file, local, remote)
@@ -926,7 +925,7 @@ int pcap_startcapture_remote(pcap_t *fp)
 
        struct pcap_md *md;                     /* structure used when doing a 
remote live capture */
 
-       md = (struct pcap_md *) ((u_char*)fp->priv + sizeof(struct pcap_win));
+       md = (struct pcap_md *)fp->priv_md;
 
        /*
         * Let's check if sampling has been required.
@@ -1386,8 +1385,7 @@ static int pcap_updatefilter_remote(pcap_t *fp, struct 
bpf_program *prog)
        struct rpcap_header header;             /* To keep the reply message */
        struct pcap_md *md;                             /* structure used when 
doing a remote live capture */
 
-       md = (struct pcap_md *) ((u_char*)fp->priv + sizeof(struct pcap_win));
-
+       md = (struct pcap_md *)fp->priv_md;
 
        if (sock_bufferize(NULL, sizeof(struct rpcap_header), NULL, &sendbufidx,
                RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, fp->errbuf, 
PCAP_ERRBUF_SIZE))
@@ -1449,7 +1447,7 @@ static int pcap_setfilter_remote(pcap_t *fp, struct 
bpf_program *prog)
 {
        struct pcap_md *md;                             /* structure used when 
doing a remote live capture */
 
-       md = (struct pcap_md *) ((u_char*)fp->priv + sizeof(struct pcap_win));
+       md = (struct pcap_md *)fp->priv_md;
 
        if (!md->rmt_capstarted)
        {
@@ -1482,7 +1480,7 @@ static int pcap_createfilter_norpcappkt(pcap_t *fp, 
struct bpf_program *prog)
        int RetVal = 0;
        struct pcap_md *md;                             /* structure used when 
doing a remote live capture */
 
-       md = (struct pcap_md *) ((u_char*)fp->priv + sizeof(struct pcap_win));
+       md = (struct pcap_md *)fp->priv_md;
 
        /* We do not want to capture our RPCAP traffic. So, let's update the 
filter */
        if (md->rmt_flags & PCAP_OPENFLAG_NOCAPTURE_RPCAP)
@@ -1600,7 +1598,7 @@ static int pcap_setsampling_remote(pcap_t *p)
        struct rpcap_sampling *sampling_pars;   /* Structure that is needed to 
send sampling parameters to the remote host */
        struct pcap_md *md;                             /* structure used when 
doing a remote live capture */
 
-       md = (struct pcap_md *) ((u_char*)p->priv + sizeof(struct pcap_win));
+       md = (struct pcap_md *)p->priv_md;
 
        /* If no samping is requested, return 'ok' */
        if (md->rmt_samp.method == PCAP_SAMP_NOSAMP)
diff --git a/pcap.c b/pcap.c
index 3cf4afa..c3e0714 100644
--- a/pcap.c
+++ b/pcap.c
@@ -124,6 +124,10 @@ struct rtentry;            /* declarations in <net/if.h> */
 #include "pcap-dbus.h"
 #endif
 
+#ifdef HAVE_REMOTE
+#include "pcap-rpcap.h"
+#endif
+
 static int
 pcap_not_initialized(pcap_t *pcap)
 {
@@ -1257,6 +1261,12 @@ pcap_alloc_pcap_t(char *ebuf, size_t size)
 {
        char *chunk;
        pcap_t *p;
+       size_t malloc_size;
+
+       malloc_size = sizeof(pcap_t) + size;
+#ifdef HAVE_REMOTE
+       malloc_size += sizeof(struct pcap_md);
+#endif
 
        /*
         * Allocate a chunk of memory big enough for a pcap_t
@@ -1264,13 +1274,13 @@ pcap_alloc_pcap_t(char *ebuf, size_t size)
         * structure following it is a private data structure
         * for the routines that handle this pcap_t.
         */
-       chunk = malloc(sizeof (pcap_t) + size);
+       chunk = malloc(malloc_size);
        if (chunk == NULL) {
                pcap_snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s",
                    pcap_strerror(errno));
                return (NULL);
        }
-       memset(chunk, 0, sizeof (pcap_t) + size);
+       memset(chunk, 0, malloc_size);
 
        /*
         * Get a pointer to the pcap_t at the beginning.
@@ -1292,7 +1302,9 @@ pcap_alloc_pcap_t(char *ebuf, size_t size)
                 */
                p->priv = (void *)(chunk + sizeof (pcap_t));
        }
-
+#ifdef HAVE_REMOTE
+       p->priv_md = (void *)(chunk + sizeof(pcap_t) + size);
+#endif
        return (p);
 }
 
-- 
2.10.1 (Apple Git-78)

_______________________________________________
tcpdump-workers mailing list
tcpdump-workers@lists.tcpdump.org
https://lists.sandelman.ca/mailman/listinfo/tcpdump-workers

Reply via email to