diff options
author | Philip Paeps <philip@FreeBSD.org> | 2019-10-06 04:26:37 +0000 |
---|---|---|
committer | Philip Paeps <philip@FreeBSD.org> | 2019-10-06 04:26:37 +0000 |
commit | 30a580a870fabfea51e4b970c488e58bd1515ce4 (patch) | |
tree | cf18fcdc7c1818418ee5fc375ca4ba2094583a41 /sf-pcapng.c | |
parent | d109bf9e4b609b5a0626b433e56db4a47dc530bb (diff) | |
download | src-30a580a870fabfea51e4b970c488e58bd1515ce4.tar.gz src-30a580a870fabfea51e4b970c488e58bd1515ce4.zip |
Import libpcap 1.9.1vendor/libpcap/1.9.1
Notes
Notes:
svn path=/vendor/libpcap/dist/; revision=353141
svn path=/vendor/libpcap/1.9.1/; revision=353142; tag=vendor/libpcap/1.9.1
Diffstat (limited to 'sf-pcapng.c')
-rw-r--r-- | sf-pcapng.c | 200 |
1 files changed, 118 insertions, 82 deletions
diff --git a/sf-pcapng.c b/sf-pcapng.c index 0f155afa9788..afaeb0566571 100644 --- a/sf-pcapng.c +++ b/sf-pcapng.c @@ -85,7 +85,7 @@ struct option_header { * Section Header Block. */ #define BT_SHB 0x0A0D0D0A - +#define BT_SHB_INSANE_MAX 1024U*1024U*1U /* 1MB should be enough */ struct section_header_block { bpf_u_int32 byte_order_magic; u_short major_version; @@ -197,9 +197,9 @@ typedef enum { * Per-interface information. */ struct pcap_ng_if { - u_int tsresol; /* time stamp resolution */ + uint64_t tsresol; /* time stamp resolution */ tstamp_scale_type_t scale_type; /* how to scale */ - u_int scale_factor; /* time stamp scale factor for power-of-10 tsresol */ + uint64_t scale_factor; /* time stamp scale factor for power-of-10 tsresol */ uint64_t tsoffset; /* time stamp offset */ }; @@ -223,7 +223,7 @@ struct pcap_ng_if { * so we impose a limit regardless of the size of a pointer. */ struct pcap_ng_sf { - u_int user_tsresol; /* time stamp resolution requested by the user */ + uint64_t user_tsresol; /* time stamp resolution requested by the user */ u_int max_blocksize; /* don't grow buffer size past this */ bpf_u_int32 ifcount; /* number of interfaces seen in this capture */ bpf_u_int32 ifaces_size; /* size of array below */ @@ -231,16 +231,21 @@ struct pcap_ng_sf { }; /* - * Maximum block size for a given maximum snapshot length; we calculate - * this based - * - * We define it as the size of an EPB with a max_snaplen-sized - * packet and 128KB of options. + * The maximum block size we start with; we use an arbitrary value of + * 16 MiB. + */ +#define INITIAL_MAX_BLOCKSIZE (16*1024*1024) + +/* + * Maximum block size for a given maximum snapshot length; we define it + * as the size of an EPB with a max_snaplen-sized packet and 128KB of + * options. */ -#define MAX_BLOCKSIZE(max_snaplen) (sizeof (struct block_header) + \ - sizeof (struct enhanced_packet_block) + \ - (max_snaplen) + 131072 + \ - sizeof (struct block_trailer)) +#define MAX_BLOCKSIZE_FOR_SNAPLEN(max_snaplen) \ + (sizeof (struct block_header) + \ + sizeof (struct enhanced_packet_block) + \ + (max_snaplen) + 131072 + \ + sizeof (struct block_trailer)) static void pcap_ng_cleanup(pcap_t *p); static int pcap_ng_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, @@ -261,9 +266,8 @@ read_bytes(FILE *fp, void *buf, size_t bytes_to_read, int fail_on_eof, if (amt_read == 0 && !fail_on_eof) return (0); /* EOF */ pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, - "truncated dump file; tried to read %lu bytes, only got %lu", - (unsigned long)bytes_to_read, - (unsigned long)amt_read); + "truncated pcapng dump file; tried to read %" PRIsize " bytes, only got %" PRIsize, + bytes_to_read, amt_read); } return (-1); } @@ -276,6 +280,7 @@ read_block(FILE *fp, pcap_t *p, struct block_cursor *cursor, char *errbuf) struct pcap_ng_sf *ps; int status; struct block_header bhdr; + struct block_trailer *btrlr; u_char *bdata; size_t data_remaining; @@ -291,29 +296,28 @@ read_block(FILE *fp, pcap_t *p, struct block_cursor *cursor, char *errbuf) } /* - * Is this block "too big"? - * - * We choose 16MB as "too big", for now, so that we handle - * "reasonably" large buffers but don't chew up all the - * memory if we read a malformed file. - */ - if (bhdr.total_length > 16*1024*1024) { - pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, - "pcapng block size %u > maximum %u", - bhdr.total_length, 16*1024*1024); - return (-1); - } - - /* * Is this block "too small" - i.e., is it shorter than a block * header plus a block trailer? */ if (bhdr.total_length < sizeof(struct block_header) + sizeof(struct block_trailer)) { pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, - "block in pcapng dump file has a length of %u < %lu", + "block in pcapng dump file has a length of %u < %" PRIsize, bhdr.total_length, - (unsigned long)(sizeof(struct block_header) + sizeof(struct block_trailer))); + sizeof(struct block_header) + sizeof(struct block_trailer)); + return (-1); + } + + /* + * Is the block total length a multiple of 4? + */ + if ((bhdr.total_length % 4) != 0) { + /* + * No. Report that as an error. + */ + pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, + "block in pcapng dump file has a length of %u that is not a multiple of 4" PRIsize, + bhdr.total_length); return (-1); } @@ -322,12 +326,13 @@ read_block(FILE *fp, pcap_t *p, struct block_cursor *cursor, char *errbuf) */ if (p->bufsize < bhdr.total_length) { /* - * No - make it big enough, unless it's too big. + * No - make it big enough, unless it's too big, in + * which case we fail. */ void *bigger_buffer; if (bhdr.total_length > ps->max_blocksize) { - pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "block is larger than maximum block size %u", + pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "pcapng block size %u > maximum %u", bhdr.total_length, ps->max_blocksize); return (-1); } @@ -350,6 +355,26 @@ read_block(FILE *fp, pcap_t *p, struct block_cursor *cursor, char *errbuf) return (-1); /* + * Get the block size from the trailer. + */ + btrlr = (struct block_trailer *)(bdata + data_remaining - sizeof (struct block_trailer)); + if (p->swapped) + btrlr->total_length = SWAPLONG(btrlr->total_length); + + /* + * Is the total length from the trailer the same as the total + * length from the header? + */ + if (bhdr.total_length != btrlr->total_length) { + /* + * No. + */ + pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, + "block total length in header and trailer don't match"); + return (-1); + } + + /* * Initialize the cursor. */ cursor->data = bdata; @@ -431,13 +456,13 @@ get_optvalue_from_block_data(struct block_cursor *cursor, } static int -process_idb_options(pcap_t *p, struct block_cursor *cursor, u_int *tsresol, +process_idb_options(pcap_t *p, struct block_cursor *cursor, uint64_t *tsresol, uint64_t *tsoffset, int *is_binary, char *errbuf) { struct option_header *opthdr; void *optvalue; int saw_tsresol, saw_tsoffset; - u_char tsresol_opt; + uint8_t tsresol_opt; u_int i; saw_tsresol = 0; @@ -495,31 +520,42 @@ process_idb_options(pcap_t *p, struct block_cursor *cursor, u_int *tsresol, /* * Resolution is negative power of 2. */ + uint8_t tsresol_shift = (tsresol_opt & 0x7F); + + if (tsresol_shift > 63) { + /* + * Resolution is too high; 2^-{res} + * won't fit in a 64-bit value. + */ + pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, + "Interface Description Block if_tsresol option resolution 2^-%u is too high", + tsresol_shift); + return (-1); + } *is_binary = 1; - *tsresol = 1 << (tsresol_opt & 0x7F); + *tsresol = ((uint64_t)1) << tsresol_shift; } else { /* * Resolution is negative power of 10. */ - *is_binary = 0; - *tsresol = 1; - for (i = 0; i < tsresol_opt; i++) - *tsresol *= 10; - } - if (*tsresol == 0) { - /* - * Resolution is too high. - */ - if (tsresol_opt & 0x80) { - pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, - "Interface Description Block if_tsresol option resolution 2^-%u is too high", - tsresol_opt & 0x7F); - } else { + if (tsresol_opt > 19) { + /* + * Resolution is too high; 2^-{res} + * won't fit in a 64-bit value (the + * largest power of 10 that fits + * in a 64-bit value is 10^19, as + * the largest 64-bit unsigned + * value is ~1.8*10^19). + */ pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Interface Description Block if_tsresol option resolution 10^-%u is too high", tsresol_opt); + return (-1); } - return (-1); + *is_binary = 0; + *tsresol = 1; + for (i = 0; i < tsresol_opt; i++) + *tsresol *= 10; } break; @@ -554,7 +590,7 @@ static int add_interface(pcap_t *p, struct block_cursor *cursor, char *errbuf) { struct pcap_ng_sf *ps; - u_int tsresol; + uint64_t tsresol; uint64_t tsoffset; int is_binary; @@ -725,9 +761,10 @@ add_interface(pcap_t *p, struct block_cursor *cursor, char *errbuf) * relevant information from the header. */ pcap_t * -pcap_ng_check_header(bpf_u_int32 magic, FILE *fp, u_int precision, char *errbuf, - int *err) +pcap_ng_check_header(const uint8_t *magic, FILE *fp, u_int precision, + char *errbuf, int *err) { + bpf_u_int32 magic_int; size_t amt_read; bpf_u_int32 total_length; bpf_u_int32 byte_order_magic; @@ -749,7 +786,8 @@ pcap_ng_check_header(bpf_u_int32 magic, FILE *fp, u_int precision, char *errbuf, * Check whether the first 4 bytes of the file are the block * type for a pcapng savefile. */ - if (magic != BT_SHB) { + memcpy(&magic_int, magic, sizeof(magic_int)); + if (magic_int != BT_SHB) { /* * XXX - check whether this looks like what the block * type would be after being munged by mapping between @@ -818,11 +856,14 @@ pcap_ng_check_header(bpf_u_int32 magic, FILE *fp, u_int precision, char *errbuf, /* * Check the sanity of the total length. */ - if (total_length < sizeof(*bhdrp) + sizeof(*shbp) + sizeof(struct block_trailer)) { + if (total_length < sizeof(*bhdrp) + sizeof(*shbp) + sizeof(struct block_trailer) || + (total_length > BT_SHB_INSANE_MAX)) { pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, - "Section Header Block in pcapng dump file has a length of %u < %lu", + "Section Header Block in pcapng dump file has invalid length %" PRIsize " < _%u_ < %u (BT_SHB_INSANE_MAX)", + sizeof(*bhdrp) + sizeof(*shbp) + sizeof(struct block_trailer), total_length, - (unsigned long)(sizeof(*bhdrp) + sizeof(*shbp) + sizeof(struct block_trailer))); + BT_SHB_INSANE_MAX); + *err = 1; return (NULL); } @@ -874,10 +915,10 @@ pcap_ng_check_header(bpf_u_int32 magic, FILE *fp, u_int precision, char *errbuf, * leaving room for some options. * * If we find a bigger block, we reallocate the buffer, up to - * the maximum size. We start out with a maximum size based - * on a maximum snapshot length of MAXIMUM_SNAPLEN; if we see - * any link-layer header types with a larger maximum snapshot - * length, we boost the maximum. + * the maximum size. We start out with a maximum size of + * INITIAL_MAX_BLOCKSIZE; if we see any link-layer header types + * with a maximum snapshot that results in a larger maximum + * block length, we boost the maximum. */ p->bufsize = 2048; if (p->bufsize < total_length) @@ -889,7 +930,7 @@ pcap_ng_check_header(bpf_u_int32 magic, FILE *fp, u_int precision, char *errbuf, *err = 1; return (NULL); } - ps->max_blocksize = MAX_BLOCKSIZE(MAXIMUM_SNAPLEN); + ps->max_blocksize = INITIAL_MAX_BLOCKSIZE; /* * Copy the stuff we've read to the buffer, and read the rest @@ -897,12 +938,12 @@ pcap_ng_check_header(bpf_u_int32 magic, FILE *fp, u_int precision, char *errbuf, */ bhdrp = (struct block_header *)p->buffer; shbp = (struct section_header_block *)((u_char *)p->buffer + sizeof(struct block_header)); - bhdrp->block_type = magic; + bhdrp->block_type = magic_int; bhdrp->total_length = total_length; shbp->byte_order_magic = byte_order_magic; if (read_bytes(fp, - (u_char *)p->buffer + (sizeof(magic) + sizeof(total_length) + sizeof(byte_order_magic)), - total_length - (sizeof(magic) + sizeof(total_length) + sizeof(byte_order_magic)), + (u_char *)p->buffer + (sizeof(magic_int) + sizeof(total_length) + sizeof(byte_order_magic)), + total_length - (sizeof(magic_int) + sizeof(total_length) + sizeof(byte_order_magic)), 1, errbuf) == -1) goto fail; @@ -999,19 +1040,8 @@ pcap_ng_check_header(bpf_u_int32 magic, FILE *fp, u_int precision, char *errbuf, done: p->tzoff = 0; /* XXX - not used in pcap */ - p->snapshot = idbp->snaplen; - if (p->snapshot <= 0) { - /* - * Bogus snapshot length; use the maximum for this - * link-layer type as a fallback. - * - * XXX - the only reason why snapshot is signed is - * that pcap_snapshot() returns an int, not an - * unsigned int. - */ - p->snapshot = max_snaplen_for_dlt(idbp->linktype); - } p->linktype = linktype_to_dlt(idbp->linktype); + p->snapshot = pcap_adjust_snapshot(p->linktype, idbp->snaplen); p->linktype_ext = 0; /* @@ -1019,8 +1049,8 @@ done: * snapshot length for this DLT_ is bigger than the current * maximum block size, increase the maximum. */ - if (MAX_BLOCKSIZE(max_snaplen_for_dlt(p->linktype)) > ps->max_blocksize) - ps->max_blocksize = MAX_BLOCKSIZE(max_snaplen_for_dlt(p->linktype)); + if (MAX_BLOCKSIZE_FOR_SNAPLEN(max_snaplen_for_dlt(p->linktype)) > ps->max_blocksize) + ps->max_blocksize = MAX_BLOCKSIZE_FOR_SNAPLEN(max_snaplen_for_dlt(p->linktype)); p->next_packet_op = pcap_ng_next_packet; p->cleanup_op = pcap_ng_cleanup; @@ -1206,7 +1236,13 @@ pcap_ng_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data) idbp->linktype); return (-1); } - if ((bpf_u_int32)p->snapshot != idbp->snaplen) { + + /* + * Check against the *adjusted* value of this IDB's + * snapshot length. + */ + if ((bpf_u_int32)p->snapshot != + pcap_adjust_snapshot(p->linktype, idbp->snaplen)) { pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "an interface has a snapshot length %u different from the type of the first interface", idbp->snaplen); |