summaryrefslogtreecommitdiffstats
path: root/freebsd/contrib/libpcap/sf-pcapng.c
diff options
context:
space:
mode:
Diffstat (limited to 'freebsd/contrib/libpcap/sf-pcapng.c')
-rw-r--r--freebsd/contrib/libpcap/sf-pcapng.c200
1 files changed, 118 insertions, 82 deletions
diff --git a/freebsd/contrib/libpcap/sf-pcapng.c b/freebsd/contrib/libpcap/sf-pcapng.c
index f5719042..bfc43241 100644
--- a/freebsd/contrib/libpcap/sf-pcapng.c
+++ b/freebsd/contrib/libpcap/sf-pcapng.c
@@ -87,7 +87,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;
@@ -199,9 +199,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 */
};
@@ -225,7 +225,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 */
@@ -233,16 +233,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,
@@ -263,9 +268,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);
}
@@ -278,6 +282,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;
@@ -293,29 +298,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);
}
@@ -324,12 +328,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);
}
@@ -352,6 +357,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;
@@ -433,13 +458,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;
@@ -497,31 +522,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;
@@ -556,7 +592,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;
@@ -727,9 +763,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;
@@ -751,7 +788,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
@@ -820,11 +858,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);
}
@@ -876,10 +917,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)
@@ -891,7 +932,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
@@ -899,12 +940,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;
@@ -1001,19 +1042,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;
/*
@@ -1021,8 +1051,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;
@@ -1208,7 +1238,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);