aboutsummaryrefslogtreecommitdiffstats
path: root/wiretap
diff options
context:
space:
mode:
authorGuy Harris <guy@alum.mit.edu>2013-06-07 08:19:40 +0000
committerGuy Harris <guy@alum.mit.edu>2013-06-07 08:19:40 +0000
commit2429df9c51301859602df1476e391682d665f677 (patch)
tree932e831941da694fd252f1f74c4d078fe62451d0 /wiretap
parente4893f0448eb85045fdc775958b1c4f6ae2ce7b7 (diff)
Prevent attempts to allocate huge amounts of memory by imposing an
artificial 16MB limit on blocks. Do some sanity checks when reading options, to make sure we don't read past the end of the block. Make some variables unsigned so as not to get inappropriate sign-extension (which, in practice, should never happen due to the 16MB block size limit, although if the limit is raised above 2^31-1, the limit won't protect you). Fixes bug 8752. svn path=/trunk/; revision=49833
Diffstat (limited to 'wiretap')
-rw-r--r--wiretap/pcapng.c164
1 files changed, 141 insertions, 23 deletions
diff --git a/wiretap/pcapng.c b/wiretap/pcapng.c
index 074b2d92a9..23c42dce0c 100644
--- a/wiretap/pcapng.c
+++ b/wiretap/pcapng.c
@@ -104,6 +104,18 @@ typedef struct pcapng_block_header_s {
*/
#define MIN_BLOCK_SIZE ((guint32)(sizeof(pcapng_block_header_t) + sizeof(guint32)))
+/*
+ * In order to keep from trying to allocate large chunks of memory,
+ * which could either fail or, even if it succeeds, chew up so much
+ * address space or memory+backing store as not to leave room for
+ * anything else, we impose an upper limit on the size of blocks
+ * we're willing to handle.
+ *
+ * For now, we pick an arbitrary limit of 16MB (OK, fine, 16MiB, but
+ * don't try saying that on Wikipedia :-) :-) :-)).
+ */
+#define MAX_BLOCK_SIZE (16*1024*1024)
+
/* pcapng: section header block */
typedef struct pcapng_section_header_block_s {
/* pcapng_block_header_t */
@@ -393,22 +405,29 @@ typedef struct {
static int
pcapng_read_option(FILE_T fh, pcapng_t *pn, pcapng_option_header_t *oh,
- char *content, int len, int *err, gchar **err_info)
+ char *content, guint len, guint to_read,
+ int *err, gchar **err_info)
{
int bytes_read;
int block_read;
guint64 file_offset64;
+ /* sanity check: don't run past the end of the block */
+ if (to_read < sizeof (*oh)) {
+ *err = WTAP_ERR_BAD_FILE;
+ *err_info = g_strdup("pcapng_read_option: option goes past the end of the block");
+ return -1;
+ }
/* read option header */
errno = WTAP_ERR_CANT_READ;
bytes_read = file_read(oh, sizeof (*oh), fh);
if (bytes_read != sizeof (*oh)) {
- pcapng_debug0("pcapng_read_option: failed to read option");
- *err = file_error(fh, err_info);
- if (*err != 0)
- return -1;
- return 0;
+ pcapng_debug0("pcapng_read_option: failed to read option");
+ *err = file_error(fh, err_info);
+ if (*err != 0)
+ return -1;
+ return 0;
}
block_read = sizeof (*oh);
if (pn->byte_swapped) {
@@ -416,6 +435,13 @@ pcapng_read_option(FILE_T fh, pcapng_t *pn, pcapng_option_header_t *oh,
oh->option_length = BSWAP16(oh->option_length);
}
+ /* sanity check: don't run past the end of the block */
+ if (to_read < sizeof (*oh) + oh->option_length) {
+ *err = WTAP_ERR_BAD_FILE;
+ *err_info = g_strdup("pcapng_read_option: option goes past the end of the block");
+ return -1;
+ }
+
/* sanity check: option length */
if (oh->option_length > len) {
pcapng_debug2("pcapng_read_option: option_length %u larger than buffer (%u)",
@@ -457,8 +483,8 @@ pcapng_read_section_header_block(FILE_T fh, gboolean first_block,
gchar **err_info)
{
int bytes_read;
- int block_read;
- int to_read, opt_cont_buf_len;
+ guint block_read;
+ guint to_read, opt_cont_buf_len;
pcapng_section_header_block_t shb;
pcapng_option_header_t oh;
char *option_content = NULL; /* Allocate as large as the options block */
@@ -539,7 +565,23 @@ pcapng_read_section_header_block(FILE_T fh, gboolean first_block,
return 0;
}
- /* OK, at this point we assume it's a pcap-ng file. */
+ /* OK, at this point we assume it's a pcap-ng file.
+
+ Don't try to allocate memory for a huge number of options, as
+ that might fail and, even if it succeeds, it might not leave
+ any address space or memory+backing store for anything else.
+
+ We do that by imposing a maximum block size of MAX_BLOCK_SIZE.
+ We check for this *after* checking the SHB for its byte
+ order magic number, so that non-pcap-ng files are less
+ likely to be treated as bad pcap-ng files. */
+ if (bh->block_total_length > MAX_BLOCK_SIZE) {
+ *err = WTAP_ERR_BAD_FILE;
+ *err_info = g_strdup_printf("pcapng: total block length %u is too large (> %u)",
+ bh->block_total_length, MAX_BLOCK_SIZE);
+ return -1;
+ }
+
/* We currently only suport one SHB */
if (pn->shb_read == TRUE) {
*err = WTAP_ERR_UNSUPPORTED;
@@ -572,14 +614,15 @@ pcapng_read_section_header_block(FILE_T fh, gboolean first_block,
/* Options */
errno = WTAP_ERR_CANT_READ;
to_read = bh->block_total_length - MIN_SHB_SIZE;
+
/* Allocate enough memory to hold all options */
opt_cont_buf_len = to_read;
option_content = (char *)g_malloc(opt_cont_buf_len);
pcapng_debug1("pcapng_read_section_header_block: Options %u bytes", to_read);
- while (to_read > 0) {
+ while (to_read != 0) {
/* read option */
pcapng_debug1("pcapng_read_section_header_block: Options %u bytes remaining", to_read);
- bytes_read = pcapng_read_option(fh, pn, &oh, option_content, opt_cont_buf_len, err, err_info);
+ bytes_read = pcapng_read_option(fh, pn, &oh, option_content, opt_cont_buf_len, to_read, err, err_info);
if (bytes_read <= 0) {
pcapng_debug0("pcapng_read_section_header_block: failed to read option");
return bytes_read;
@@ -646,8 +689,8 @@ pcapng_read_if_descr_block(FILE_T fh, pcapng_block_header_t *bh, pcapng_t *pn,
{
guint64 time_units_per_second = 1000000; /* default */
int bytes_read;
- int block_read;
- int to_read, opt_cont_buf_len;
+ guint block_read;
+ guint to_read, opt_cont_buf_len;
pcapng_interface_description_block_t idb;
pcapng_option_header_t oh;
char *option_content = NULL; /* Allocate as large as the options block */
@@ -665,6 +708,21 @@ pcapng_read_if_descr_block(FILE_T fh, pcapng_block_header_t *bh, pcapng_t *pn,
return -1;
}
+ /* Don't try to allocate memory for a huge number of options, as
+ that might fail and, even if it succeeds, it might not leave
+ any address space or memory+backing store for anything else.
+
+ We do that by imposing a maximum block size of MAX_BLOCK_SIZE.
+ We check for this *after* checking the SHB for its byte
+ order magic number, so that non-pcap-ng files are less
+ likely to be treated as bad pcap-ng files. */
+ if (bh->block_total_length > MAX_BLOCK_SIZE) {
+ *err = WTAP_ERR_BAD_FILE;
+ *err_info = g_strdup_printf("pcapng: total block length %u is too large (> %u)",
+ bh->block_total_length, MAX_BLOCK_SIZE);
+ return -1;
+ }
+
/* read block content */
errno = WTAP_ERR_CANT_READ;
bytes_read = file_read(&idb, sizeof idb, fh);
@@ -730,9 +788,9 @@ pcapng_read_if_descr_block(FILE_T fh, pcapng_block_header_t *bh, pcapng_t *pn,
opt_cont_buf_len = to_read;
option_content = (char *)g_malloc(opt_cont_buf_len);
- while (to_read > 0) {
+ while (to_read != 0) {
/* read option */
- bytes_read = pcapng_read_option(fh, pn, &oh, option_content, opt_cont_buf_len, err, err_info);
+ bytes_read = pcapng_read_option(fh, pn, &oh, option_content, opt_cont_buf_len, to_read, err, err_info);
if (bytes_read <= 0) {
pcapng_debug0("pcapng_read_if_descr_block: failed to read option");
return bytes_read;
@@ -897,8 +955,8 @@ static int
pcapng_read_packet_block(FILE_T fh, pcapng_block_header_t *bh, pcapng_t *pn, wtapng_block_t *wblock, int *err, gchar **err_info, gboolean enhanced)
{
int bytes_read;
- int block_read;
- int to_read, opt_cont_buf_len;
+ guint block_read;
+ guint to_read, opt_cont_buf_len;
guint64 file_offset64;
pcapng_enhanced_packet_block_t epb;
pcapng_packet_block_t pb;
@@ -911,6 +969,21 @@ pcapng_read_packet_block(FILE_T fh, pcapng_block_header_t *bh, pcapng_t *pn, wta
char *option_content = NULL; /* Allocate as large as the options block */
int fcslen;
+ /* Don't try to allocate memory for a huge number of options, as
+ that might fail and, even if it succeeds, it might not leave
+ any address space or memory+backing store for anything else.
+
+ We do that by imposing a maximum block size of MAX_BLOCK_SIZE.
+ We check for this *after* checking the SHB for its byte
+ order magic number, so that non-pcap-ng files are less
+ likely to be treated as bad pcap-ng files. */
+ if (bh->block_total_length > MAX_BLOCK_SIZE) {
+ *err = WTAP_ERR_BAD_FILE;
+ *err_info = g_strdup_printf("pcapng: total block length %u is too large (> %u)",
+ bh->block_total_length, MAX_BLOCK_SIZE);
+ return -1;
+ }
+
/* "(Enhanced) Packet Block" read fixed part */
errno = WTAP_ERR_CANT_READ;
if (enhanced) {
@@ -1143,9 +1216,9 @@ pcapng_read_packet_block(FILE_T fh, pcapng_block_header_t *bh, pcapng_t *pn, wta
opt_cont_buf_len = to_read;
option_content = (char *)g_malloc(opt_cont_buf_len);
- while (to_read > 0) {
+ while (to_read != 0) {
/* read option */
- bytes_read = pcapng_read_option(fh, pn, &oh, option_content, opt_cont_buf_len, err, err_info);
+ bytes_read = pcapng_read_option(fh, pn, &oh, option_content, opt_cont_buf_len, to_read, err, err_info);
if (bytes_read <= 0) {
pcapng_debug0("pcapng_read_packet_block: failed to read option");
return bytes_read;
@@ -1248,6 +1321,21 @@ pcapng_read_simple_packet_block(FILE_T fh, pcapng_block_header_t *bh, pcapng_t *
return -1;
}
+ /* Don't try to allocate memory for a huge number of options, as
+ that might fail and, even if it succeeds, it might not leave
+ any address space or memory+backing store for anything else.
+
+ We do that by imposing a maximum block size of MAX_BLOCK_SIZE.
+ We check for this *after* checking the SHB for its byte
+ order magic number, so that non-pcap-ng files are less
+ likely to be treated as bad pcap-ng files. */
+ if (bh->block_total_length > MAX_BLOCK_SIZE) {
+ *err = WTAP_ERR_BAD_FILE;
+ *err_info = g_strdup_printf("pcapng: total block length %u is too large (> %u)",
+ bh->block_total_length, MAX_BLOCK_SIZE);
+ return -1;
+ }
+
/* "Simple Packet Block" read fixed part */
errno = WTAP_ERR_CANT_READ;
bytes_read = file_read(&spb, sizeof spb, fh);
@@ -1431,6 +1519,21 @@ pcapng_read_name_resolution_block(FILE_T fh, pcapng_block_header_t *bh, pcapng_t
return -1;
}
+ /* Don't try to allocate memory for a huge number of options, as
+ that might fail and, even if it succeeds, it might not leave
+ any address space or memory+backing store for anything else.
+
+ We do that by imposing a maximum block size of MAX_BLOCK_SIZE.
+ We check for this *after* checking the SHB for its byte
+ order magic number, so that non-pcap-ng files are less
+ likely to be treated as bad pcap-ng files. */
+ if (bh->block_total_length > MAX_BLOCK_SIZE) {
+ *err = WTAP_ERR_BAD_FILE;
+ *err_info = g_strdup_printf("pcapng: total block length %u is too large (> %u)",
+ bh->block_total_length, MAX_BLOCK_SIZE);
+ return -1;
+ }
+
errno = WTAP_ERR_CANT_READ;
to_read = bh->block_total_length - 8 - 4; /* We have read the header adn should not read the final block_total_length */
@@ -1635,8 +1738,8 @@ static int
pcapng_read_interface_statistics_block(FILE_T fh, pcapng_block_header_t *bh, pcapng_t *pn, wtapng_block_t *wblock,int *err, gchar **err_info)
{
int bytes_read;
- int block_read;
- int to_read, opt_cont_buf_len;
+ guint block_read;
+ guint to_read, opt_cont_buf_len;
pcapng_interface_statistics_block_t isb;
pcapng_option_header_t oh;
char *option_content = NULL; /* Allocate as large as the options block */
@@ -1654,6 +1757,21 @@ pcapng_read_interface_statistics_block(FILE_T fh, pcapng_block_header_t *bh, pca
return -1;
}
+ /* Don't try to allocate memory for a huge number of options, as
+ that might fail and, even if it succeeds, it might not leave
+ any address space or memory+backing store for anything else.
+
+ We do that by imposing a maximum block size of MAX_BLOCK_SIZE.
+ We check for this *after* checking the SHB for its byte
+ order magic number, so that non-pcap-ng files are less
+ likely to be treated as bad pcap-ng files. */
+ if (bh->block_total_length > MAX_BLOCK_SIZE) {
+ *err = WTAP_ERR_BAD_FILE;
+ *err_info = g_strdup_printf("pcapng: total block length %u is too large (> %u)",
+ bh->block_total_length, MAX_BLOCK_SIZE);
+ return -1;
+ }
+
/* "Interface Statistics Block" read fixed part */
errno = WTAP_ERR_CANT_READ;
bytes_read = file_read(&isb, sizeof isb, fh);
@@ -1692,9 +1810,9 @@ pcapng_read_interface_statistics_block(FILE_T fh, pcapng_block_header_t *bh, pca
opt_cont_buf_len = to_read;
option_content = (char *)g_malloc(opt_cont_buf_len);
- while (to_read > 0) {
+ while (to_read != 0) {
/* read option */
- bytes_read = pcapng_read_option(fh, pn, &oh, option_content, opt_cont_buf_len, err, err_info);
+ bytes_read = pcapng_read_option(fh, pn, &oh, option_content, opt_cont_buf_len, to_read, err, err_info);
if (bytes_read <= 0) {
pcapng_debug0("pcapng_read_interface_statistics_block: failed to read option");
return bytes_read;