CVE-2016-5356 (published 2016-08-07T16:59Z)

wiretap/cosine.c in the CoSine file parser in Wireshark 1.12.x before 1.12.12 and 2.x before 2.0.4 mishandles sscanf unsigned-integer processing, which allows remote attackers to cause a denial of service (application crash) via a crafted file.

Severity: MEDIUM
CVSS v2 base score: 4.3 (AV:N/AC:M/Au:N/C:N/I:N/A:P)
CVSS v3 base score: 5.9, MEDIUM (CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:H)

Weakness information:
cwe_id: CWE-119
cwe_name: Improper Restriction of Operations within the Bounds of a Memory Buffer
description: The product performs operations on a memory buffer, but it reads from or writes to a memory location outside the buffer's intended boundary. This may result in read or write operations on unexpected memory locations that could be linked to other variables, data structures, or internal program data.
extended_description: 
            Certain languages allow direct addressing of memory locations and do not automatically ensure that these locations are valid for the memory buffer that is being referenced. This can cause read or write operations to be performed on memory locations that may be associated with other variables, data structures, or internal program data.
         
         

Fix information:
repo_url: https://github.com/wireshark/wireshark
commit_details: repo_url: https://github.com/wireshark/wireshark
author: Guy Harris
author_date: 2016-04-29 15:46:58-07:00
msg: Fix packet length handling.

Treat the packet length as unsigned - it shouldn't be negative in the
file.  If it is, that'll probably cause the sscanf to fail, so we'll
report the file as bad.

Check it against WTAP_MAX_PACKET_SIZE to make sure we don't try to
allocate a huge amount of memory, just as we do in other file readers.

Use the now-validated packet size as the length in
ws_buffer_assure_space(), so we are certain to have enough space, and
don't allocate too much space.

Merge the header and packet data parsing routines while we're at it.

Bug: 12395
Change-Id: Ia70f33b71ff28451190fcf144c333fd1362646b2
Reviewed-on: https://code.wireshark.org/review/15172
Reviewed-by: Guy Harris <guy@alum.mit.edu>
repository: repo_url: https://github.com/wireshark/wireshark
repo_name: wireshark/wireshark
description: Read-only mirror of Wireshark's Git repository at https://gitlab.com/wireshark/wireshark. ⚠️ GitHub won't let us disable pull requests. ⚠️ THEY WILL BE IGNORED HERE ⚠️ Upload them at GitLab instead.
repo_language: C
owner: wireshark
file_changes: filename: cosine.c
change_type: ModificationType.MODIFY
diff: @@ -157,8 +157,6 @@
 #define COSINE_HEADER_LINES_TO_CHECK	200
 #define COSINE_LINE_LENGTH		240
 
-#define COSINE_MAX_PACKET_LEN	65536
-
 static gboolean empty_line(const gchar *line);
 static gint64 cosine_seek_next_packet(wtap *wth, int *err, gchar **err_info,
 	char *hdr);
@@ -167,10 +165,8 @@ static gboolean cosine_read(wtap *wth, int *err, gchar **err_info,
 	gint64 *data_offset);
 static gboolean cosine_seek_read(wtap *wth, gint64 seek_off,
 	struct wtap_pkthdr *phdr, Buffer *buf, int *err, gchar **err_info);
-static int parse_cosine_rec_hdr(struct wtap_pkthdr *phdr, const char *line,
-	int *err, gchar **err_info);
-static gboolean parse_cosine_hex_dump(FILE_T fh, struct wtap_pkthdr *phdr,
-	int pkt_len, Buffer* buf, int *err, gchar **err_info);
+static int parse_cosine_packet(FILE_T fh, struct wtap_pkthdr *phdr, Buffer* buf,
+	char *line, int *err, gchar **err_info);
 static int parse_single_hex_dump_line(char* rec, guint8 *buf,
 	guint byte_offset);
 
@@ -287,7 +283,6 @@ static gboolean cosine_read(wtap *wth, int *err, gchar **err_info,
     gint64 *data_offset)
 {
 	gint64	offset;
-	int	pkt_len;
 	char	line[COSINE_LINE_LENGTH];
 
 	/* Find the next packet */
@@ -296,14 +291,9 @@ static gboolean cosine_read(wtap *wth, int *err, gchar **err_info,
 		return FALSE;
 	*data_offset = offset;
 
-	/* Parse the header */
-	pkt_len = parse_cosine_rec_hdr(&wth->phdr, line, err, err_info);
-	if (pkt_len == -1)
-		return FALSE;
-
-	/* Convert the ASCII hex dump to binary data */
-	return parse_cosine_hex_dump(wth->fh, &wth->phdr, pkt_len,
-	    wth->frame_buffer, err, err_info);
+	/* Parse the header and convert the ASCII hex dump to binary data */
+	return parse_cosine_packet(wth->fh, &wth->phdr, wth->frame_buffer,
+	    line, err, err_info);
 }
 
 /* Used to read packets in random-access fashion */
@@ -311,7 +301,6 @@ static gboolean
 cosine_seek_read(wtap *wth, gint64 seek_off, struct wtap_pkthdr *phdr,
 	Buffer *buf, int *err, gchar **err_info)
 {
-	int	pkt_len;
 	char	line[COSINE_LINE_LENGTH];
 
 	if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
@@ -325,13 +314,8 @@ cosine_seek_read(wtap *wth, gint64 seek_off, struct wtap_pkthdr *phdr,
 		return FALSE;
 	}
 
-	/* Parse the header */
-	pkt_len = parse_cosine_rec_hdr(phdr, line, err, err_info);
-	if (pkt_len == -1)
-		return FALSE;
-
-	/* Convert the ASCII hex dump to binary data */
-	return parse_cosine_hex_dump(wth->random_fh, phdr, pkt_len, buf, err,
+	/* Parse the header and convert the ASCII hex dump to binary data */
+	return parse_cosine_packet(wth->random_fh, phdr, buf, line, err,
 	    err_info);
 }
 
@@ -340,23 +324,26 @@ cosine_seek_read(wtap *wth, gint64 seek_off, struct wtap_pkthdr *phdr,
         2002-5-10,20:1:31.4:  l2-tx (FR:3/7/1:1), Length:18, Pro:0, Off:0, Pri:0, RM:0, Err:0 [0x4000, 0x0]
     2) output to PE without date and time
         l2-tx (FR:3/7/1:1), Length:18, Pro:0, Off:0, Pri:0, RM:0, Err:0 [0x4000, 0x0] */
-static int
-parse_cosine_rec_hdr(struct wtap_pkthdr *phdr, const char *line,
-     int *err, gchar **err_info)
+static gboolean
+parse_cosine_packet(FILE_T fh, struct wtap_pkthdr *phdr, Buffer *buf,
+    char *line, int *err, gchar **err_info)
 {
 	union wtap_pseudo_header *pseudo_header = &phdr->pseudo_header;
 	int	num_items_scanned;
-	int	yy, mm, dd, hr, min, sec, csec, pkt_len;
+	int	yy, mm, dd, hr, min, sec, csec;
+	guint	pkt_len;
 	int	pro, off, pri, rm, error;
 	guint	code1, code2;
 	char	if_name[COSINE_MAX_IF_NAME_LEN] = "", direction[6] = "";
 	struct	tm tm;
+	guint8 *pd;
+	int	i, hex_lines, n, caplen = 0;
 
 	if (sscanf(line, "%4d-%2d-%2d,%2d:%2d:%2d.%9d:",
 		   &yy, &mm, &dd, &hr, &min, &sec, &csec) == 7) {
 		/* appears to be output to a control blade */
 		num_items_scanned = sscanf(line,
-		   "%4d-%2d-%2d,%2d:%2d:%2d.%9d: %5s (%127[A-Za-z0-9/:]), Length:%9d, Pro:%9d, Off:%9d, Pri:%9d, RM:%9d, Err:%9d [%8x, %8x]",
+		   "%4d-%2d-%2d,%2d:%2d:%2d.%9d: %5s (%127[A-Za-z0-9/:]), Length:%9u, Pro:%9d, Off:%9d, Pri:%9d, RM:%9d, Err:%9d [%8x, %8x]",
 			&yy, &mm, &dd, &hr, &min, &sec, &csec,
 				   direction, if_name, &pkt_len,
 				   &pro, &off, &pri, &rm, &error,
@@ -365,12 +352,12 @@ parse_cosine_rec_hdr(struct wtap_pkthdr *phdr, const char *line,
 		if (num_items_scanned != 17) {
 			*err = WTAP_ERR_BAD_FILE;
 			*err_info = g_strdup("cosine: purported control blade line doesn't have code values");
-			return -1;
+			return FALSE;
 		}
 	} else {
 		/* appears to be output to PE */
 		num_items_scanned = sscanf(line,
-		   "%5s (%127[A-Za-z0-9/:]), Length:%9d, Pro:%9d, Off:%9d, Pri:%9d, RM:%9d, Err:%9d [%8x, %8x]",
+		   "%5s (%127[A-Za-z0-9/:]), Length:%9u, Pro:%9d, Off:%9d, Pri:%9d, RM:%9d, Err:%9d [%8x, %8x]",
 				   direction, if_name, &pkt_len,
 				   &pro, &off, &pri, &rm, &error,
 				   &code1, &code2);
@@ -378,10 +365,20 @@ parse_cosine_rec_hdr(struct wtap_pkthdr *phdr, const char *line,
 		if (num_items_scanned != 10) {
 			*err = WTAP_ERR_BAD_FILE;
 			*err_info = g_strdup("cosine: header line is neither control blade nor PE output");
-			return -1;
+			return FALSE;
 		}
 		yy = mm = dd = hr = min = sec = csec = 0;
 	}
+	if (pkt_len > WTAP_MAX_PACKET_SIZE) {
+		/*
+		 * Probably a corrupt capture file; don't blow up trying
+		 * to allocate space for an immensely-large packet.
+		 */
+		*err = WTAP_ERR_BAD_FILE;
+		*err_info = g_strdup_printf("cosine: File has %u-byte packet, bigger than maximum of %u",
+		    pkt_len, WTAP_MAX_PACKET_SIZE);
+		return FALSE;
+	}
 
 	phdr->rec_type = REC_TYPE_PACKET;
 	phdr->presence_flags = WTAP_HAS_TS|WTAP_HAS_CAP_LEN;
@@ -430,21 +427,8 @@ parse_cosine_rec_hdr(struct wtap_pkthdr *phdr, const char *line,
 	pseudo_header->cosine.rm = rm;
 	pseudo_header->cosine.err = error;
 
-	return pkt_len;
-}
-
-/* Converts ASCII hex dump to binary data. Returns TRUE on success,
-   FALSE if any error is encountered. */
-static gboolean
-parse_cosine_hex_dump(FILE_T fh, struct wtap_pkthdr *phdr, int pkt_len,
-    Buffer* buf, int *err, gchar **err_info)
-{
-	guint8 *pd;
-	gchar	line[COSINE_LINE_LENGTH];
-	int	i, hex_lines, n, caplen = 0;
-
 	/* Make sure we have enough room for the packet */
-	ws_buffer_assure_space(buf, COSINE_MAX_PACKET_LEN);
+	ws_buffer_assure_space(buf, pkt_len);
 	pd = ws_buffer_start_ptr(buf);
 
 	/* Calculate the number of hex dump lines, each
@@ -473,7 +457,6 @@ parse_cosine_hex_dump(FILE_T fh, struct wtap_pkthdr *phdr, int pkt_len,
 	return TRUE;
 }
 
-
 /* Take a string representing one line from a hex dump and converts
  * the text to binary data. We place the bytes in the buffer at the
  * specified offset.

programming_language: C++
repo_url: https://github.com/wireshark/wireshark
commit_details: repo_url: https://github.com/wireshark/wireshark
author: Guy Harris
author_date: 2016-05-01 16:22:40-07:00
msg: Don't treat the packet length as unsigned.

The scanf family of functions are as annoyingly bad at handling unsigned
numbers as strtoul() is - both of them are perfectly willing to accept a
value beginning with a negative sign as an unsigned value.  When using
strtoul(), you can compensate for this by explicitly checking for a '-'
as the first character of the string, but you can't do that with
sscanf().

So revert to having pkt_len be signed, and scanning it with %d, but
check for a negative value and fail if we see a negative value.

Bug: 12395
Change-Id: I43b458a73b0934e9a5c2c89d34eac5a8f21a7455
Reviewed-on: https://code.wireshark.org/review/15223
Reviewed-by: Guy Harris <guy@alum.mit.edu>
repository: repo_url: https://github.com/wireshark/wireshark
repo_name: wireshark/wireshark
description: Read-only mirror of Wireshark's Git repository at https://gitlab.com/wireshark/wireshark. ⚠️ GitHub won't let us disable pull requests. ⚠️ THEY WILL BE IGNORED HERE ⚠️ Upload them at GitLab instead.
repo_language: C
owner: wireshark
file_changes: filename: cosine.c
change_type: ModificationType.MODIFY
diff: @@ -330,8 +330,7 @@ parse_cosine_packet(FILE_T fh, struct wtap_pkthdr *phdr, Buffer *buf,
 {
 	union wtap_pseudo_header *pseudo_header = &phdr->pseudo_header;
 	int	num_items_scanned;
-	int	yy, mm, dd, hr, min, sec, csec;
-	guint	pkt_len;
+	int	yy, mm, dd, hr, min, sec, csec, pkt_len;
 	int	pro, off, pri, rm, error;
 	guint	code1, code2;
 	char	if_name[COSINE_MAX_IF_NAME_LEN] = "", direction[6] = "";
@@ -343,7 +342,7 @@ parse_cosine_packet(FILE_T fh, struct wtap_pkthdr *phdr, Buffer *buf,
 		   &yy, &mm, &dd, &hr, &min, &sec, &csec) == 7) {
 		/* appears to be output to a control blade */
 		num_items_scanned = sscanf(line,
-		   "%4d-%2d-%2d,%2d:%2d:%2d.%9d: %5s (%127[A-Za-z0-9/:]), Length:%9u, Pro:%9d, Off:%9d, Pri:%9d, RM:%9d, Err:%9d [%8x, %8x]",
+		   "%4d-%2d-%2d,%2d:%2d:%2d.%9d: %5s (%127[A-Za-z0-9/:]), Length:%9d, Pro:%9d, Off:%9d, Pri:%9d, RM:%9d, Err:%9d [%8x, %8x]",
 			&yy, &mm, &dd, &hr, &min, &sec, &csec,
 				   direction, if_name, &pkt_len,
 				   &pro, &off, &pri, &rm, &error,
@@ -357,7 +356,7 @@ parse_cosine_packet(FILE_T fh, struct wtap_pkthdr *phdr, Buffer *buf,
 	} else {
 		/* appears to be output to PE */
 		num_items_scanned = sscanf(line,
-		   "%5s (%127[A-Za-z0-9/:]), Length:%9u, Pro:%9d, Off:%9d, Pri:%9d, RM:%9d, Err:%9d [%8x, %8x]",
+		   "%5s (%127[A-Za-z0-9/:]), Length:%9d, Pro:%9d, Off:%9d, Pri:%9d, RM:%9d, Err:%9d [%8x, %8x]",
 				   direction, if_name, &pkt_len,
 				   &pro, &off, &pri, &rm, &error,
 				   &code1, &code2);
@@ -369,6 +368,11 @@ parse_cosine_packet(FILE_T fh, struct wtap_pkthdr *phdr, Buffer *buf,
 		}
 		yy = mm = dd = hr = min = sec = csec = 0;
 	}
+	if (pkt_len < 0) {
+		*err = WTAP_ERR_BAD_FILE;
+		*err_info = g_strdup("cosine: packet header has a negative packet length");
+		return FALSE;
+	}
 	if (pkt_len > WTAP_MAX_PACKET_SIZE) {
 		/*
 		 * Probably a corrupt capture file; don't blow up trying

programming_language: C++