diff options
author | Guy Harris <gharris@sonic.net> | 2022-06-03 18:00:22 -0700 |
---|---|---|
committer | Guy Harris <gharris@sonic.net> | 2022-06-15 19:25:03 -0700 |
commit | e17af17e6e25057a72918264428aecb67a6dd23c (patch) | |
tree | f914c62f547086ba1c1f62e2376a79ce7425fe8a | |
parent | 1c073ea17ecc34f7b858650808d9bac143e9389c (diff) | |
download | libpcap-e17af17e6e25057a72918264428aecb67a6dd23c.tar.gz |
Linux USB: fix incorrect values for the packet length.
Correctly compute the "real" length for isochronous transfers.
When reading memory-mapped Linux capture files, fix up the "real" length
field, in case the file was written by a program doing a capture with
the bug.
(backported from commit 08ab69f4fc5d432eb7de26ee8e33b40ea4b79744)
-rw-r--r-- | CMakeLists.txt | 1 | ||||
-rw-r--r-- | Makefile.in | 3 | ||||
-rw-r--r-- | pcap-common.c | 18 | ||||
-rw-r--r-- | pcap-common.h | 3 | ||||
-rw-r--r-- | pcap-usb-linux-common.c | 108 | ||||
-rw-r--r-- | pcap-usb-linux-common.h | 26 | ||||
-rw-r--r-- | pcap-usb-linux.c | 28 | ||||
-rw-r--r-- | sf-pcap.c | 2 | ||||
-rw-r--r-- | sf-pcapng.c | 2 |
9 files changed, 171 insertions, 20 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index c6894e86..c8601a65 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1062,6 +1062,7 @@ set(PROJECT_SOURCE_LIST_C nametoaddr.c optimize.c pcap-common.c + pcap-usb-linux-common.c pcap.c savefile.c sf-pcapng.c diff --git a/Makefile.in b/Makefile.in index e7410333..5dc731c3 100644 --- a/Makefile.in +++ b/Makefile.in @@ -94,7 +94,7 @@ REMOTE_C_SRC = @REMOTE_C_SRC@ COMMON_C_SRC = pcap.c gencode.c optimize.c nametoaddr.c etherent.c \ fmtutils.c \ savefile.c sf-pcap.c sf-pcapng.c pcap-common.c \ - bpf_image.c bpf_filter.c bpf_dump.c + pcap-usb-linux-common.c bpf_image.c bpf_filter.c bpf_dump.c GENERATED_C_SRC = scanner.c grammar.c LIBOBJS = @LIBOBJS@ @@ -148,6 +148,7 @@ HDR = $(PUBHDR) \ pcap-int.h \ pcap-rpcap.h \ pcap-types.h \ + pcap-usb-linux-common.h \ pflog.h \ portability.h \ ppp.h \ diff --git a/pcap-common.c b/pcap-common.c index a576da5d..3af657a7 100644 --- a/pcap-common.c +++ b/pcap-common.c @@ -36,6 +36,8 @@ #include "pflog.h" +#include "pcap-usb-linux-common.h" + #include "pcap-common.h" /* @@ -1792,3 +1794,19 @@ swap_pseudo_headers(int linktype, struct pcap_pkthdr *hdr, u_char *data) break; } } + +void +fixup_pcap_pkthdr(int linktype, struct pcap_pkthdr *hdr, u_char *data) +{ + if (linktype == DLT_USB_LINUX_MMAPPED) { + /* + * In older versions of libpcap, in memory-mapped captures, + * the "on-the-bus length" for isochronous transfers was + * miscalculated; it needed to be calculated based on the + * offsets and lengths in the descriptors, not on the raw + * URB length, but it wasn't. Recalculate it from the + * packet data. + */ + set_linux_usb_mmapped_length(hdr, data); + } +} diff --git a/pcap-common.h b/pcap-common.h index 8795a829..a779afe9 100644 --- a/pcap-common.h +++ b/pcap-common.h @@ -50,4 +50,7 @@ extern int linktype_to_dlt(int linktype); extern void swap_pseudo_headers(int linktype, struct pcap_pkthdr *hdr, u_char *data); +extern void fixup_pcap_pkthdr(int linktype, struct pcap_pkthdr *hdr, + u_char *data); + extern u_int max_snaplen_for_dlt(int dlt); diff --git a/pcap-usb-linux-common.c b/pcap-usb-linux-common.c new file mode 100644 index 00000000..ef0bb462 --- /dev/null +++ b/pcap-usb-linux-common.c @@ -0,0 +1,108 @@ +/* + * Copyright (c) 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * pcap-usb-linux-common.c - common code for everything that needs to + * deal with Linux USB captures. + */ + +#include "pcap/pcap.h" +#include "pcap/usb.h" + +#include "pcap-usb-linux-common.h" + +/* + * Compute, from the data provided by the Linux USB memory-mapped capture + * mechanism, the amount of packet data that would have been provided + * had the capture mechanism not chopped off any data at the end, if, in + * fact, it did so. + * + * Set the "unsliced length" field of the packet header to that value. + */ +void +set_linux_usb_mmapped_length(struct pcap_pkthdr *pkth, const u_char *bp) +{ + const pcap_usb_header_mmapped *hdr; + u_int bytes_left; + + bytes_left = pkth->caplen; + if (bytes_left < sizeof (pcap_usb_header_mmapped)) { + /* + * We don't have the full metadata header, so give up. + */ + return; + } + bytes_left -= sizeof (pcap_usb_header_mmapped); + + hdr = (const pcap_usb_header_mmapped *) bp; + if (hdr->data_flag) { + /* + * No data; just base the on-the-bus length on hdr->data_len + * (so that it's >= the captured length). + */ + pkth->len = sizeof(pcap_usb_header_mmapped) + hdr->data_len; + } else { + /* + * We got data; calculate the on-the-bus length based on + * the data length prior to the USB monitor device discarding + * data due to its buffer being too small. + */ + usb_isodesc *descs; + u_int pre_truncation_data_len; + + descs = (usb_isodesc *) (bp + sizeof(pcap_usb_header_mmapped)); + + /* + * For most transfers, urb_len is that amount. + */ + pre_truncation_data_len = hdr->urb_len; + if (hdr->transfer_type == URB_ISOCHRONOUS && + hdr->event_type == URB_COMPLETE && + (hdr->endpoint_number & URB_TRANSFER_IN)) { + /* + * For "this is complete" incoming isochronous + * transfer events, however, the data isn't + * contiguous, and the isochronous descriptos + * show how it's scattered. + * + * Find the end of the last chunk of data in + * the buffer referred to by the isochronous + * descriptors; that indicates how far into + * the buffer the data would have gone. + * + * Make sure we don't run past the end of the + * captured data while processing the isochronous + * descriptors. + */ + pre_truncation_data_len = 0; + for (uint32_t desc = 0; + desc < hdr->ndesc && bytes_left >= sizeof (usb_isodesc); + desc++, bytes_left -= sizeof (usb_isodesc)) { + u_int desc_end; + + desc_end = descs[desc].offset + descs[desc].len; + if (desc_end > pre_truncation_data_len) + pre_truncation_data_len = desc_end; + } + } + pkth->len = sizeof(pcap_usb_header_mmapped) + + (hdr->ndesc * sizeof (usb_isodesc)) + + pre_truncation_data_len; + } +} diff --git a/pcap-usb-linux-common.h b/pcap-usb-linux-common.h new file mode 100644 index 00000000..05fca6a3 --- /dev/null +++ b/pcap-usb-linux-common.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * pcap-usb-linux-common.h - common code for everything that needs to + * deal with Linux USB captures. + */ + +extern void set_linux_usb_mmapped_length(struct pcap_pkthdr *pkth, + const u_char *bp); diff --git a/pcap-usb-linux.c b/pcap-usb-linux.c index d62f17dd..ef495bd2 100644 --- a/pcap-usb-linux.c +++ b/pcap-usb-linux.c @@ -39,6 +39,7 @@ #include "pcap-int.h" #include "pcap-usb-linux.h" +#include "pcap-usb-linux-common.h" #include "pcap/usb.h" #include "extract.h" @@ -756,6 +757,7 @@ usb_read_linux_mmap(pcap_t *handle, int max_packets, pcap_handler callback, u_ch struct mon_bin_mfetch fetch; int32_t vec[VEC_SIZE]; struct pcap_pkthdr pkth; + u_char *bp; pcap_usb_header_mmapped* hdr; int nflush = 0; int packets = 0; @@ -839,8 +841,13 @@ usb_read_linux_mmap(pcap_t *handle, int max_packets, pcap_handler callback, u_ch * packets if we break out of the loop here. */ + /* Get a pointer to this packet's buffer */ + bp = &handlep->mmapbuf[vec[i]]; + + /* That begins with a metadata header */ + hdr = (pcap_usb_header_mmapped*) bp; + /* discard filler */ - hdr = (pcap_usb_header_mmapped*) &handlep->mmapbuf[vec[i]]; if (hdr->event_type == '@') continue; @@ -868,24 +875,7 @@ usb_read_linux_mmap(pcap_t *handle, int max_packets, pcap_handler callback, u_ch if (hdr->data_len < clen) clen = hdr->data_len; pkth.caplen = sizeof(pcap_usb_header_mmapped) + clen; - if (hdr->data_flag) { - /* - * No data; just base the on-the-wire length - * on hdr->data_len (so that it's >= the - * captured length). - */ - pkth.len = sizeof(pcap_usb_header_mmapped) + - hdr->data_len; - } else { - /* - * We got data; base the on-the-wire length - * on hdr->urb_len, so that it includes - * data discarded by the USB monitor device - * due to its buffer being too small. - */ - pkth.len = sizeof(pcap_usb_header_mmapped) + - (hdr->ndesc * sizeof (usb_isodesc)) + hdr->urb_len; - } + set_linux_usb_mmapped_length(&pkth, bp); pkth.ts.tv_sec = (time_t)hdr->ts_sec; pkth.ts.tv_usec = hdr->ts_usec; @@ -709,6 +709,8 @@ pcap_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data) if (p->swapped) swap_pseudo_headers(p->linktype, hdr, *data); + fixup_pcap_pkthdr(p->linktype, hdr, *data); + return (1); } diff --git a/sf-pcapng.c b/sf-pcapng.c index 9e0a72e5..4791b288 100644 --- a/sf-pcapng.c +++ b/sf-pcapng.c @@ -1514,5 +1514,7 @@ found: if (p->swapped) swap_pseudo_headers(p->linktype, hdr, *data); + fixup_pcap_pkthdr(p->linktype, hdr, *data); + return (1); } |