Commit message: 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: 12394
Change-Id: I4b19b95f2e1ffc96dac5c91bff6698c246f52007
Reviewed-on: https://code.wireshark.org/review/15230
Reviewed-by: Guy Harris <guy@alum.mit.edu>
CVE: CVE-2016-5355
CWE: CWE-20
Vulnerability description: wiretap/toshiba.c in the Toshiba 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.

Project: wireshark
File: toshiba.c

parse_single_hex_dump_line(char* rec, guint8 *buf, guint byte_offset) {

	int		pos, i;
	char		*s;
	unsigned long	value;
	guint16		word_value;

	/* Get the byte_offset directly from the record */
	rec[4] = '\0';
	s = rec;
	value = strtoul(s, NULL, 16);

	if (value != byte_offset) {
		return FALSE;
	}

	/* Go through the substring representing the values and:
	 *      1. Replace any spaces with '0's
	 *      2. Place \0's every 5 bytes (to terminate the string)
	 *
	 * Then read the eight sets of hex bytes
	 */

	for (pos = START_POS; pos < START_POS + HEX_LENGTH; pos++) {
		if (rec[pos] == ' ') {
			rec[pos] = '0';
		}
	}

	pos = START_POS;
	for (i = 0; i < 8; i++) {
		rec[pos+4] = '\0';

		word_value = (guint16) strtoul(&rec[pos], NULL, 16);
		buf[byte_offset + i * 2 + 0] = (guint8) (word_value >> 8);
		buf[byte_offset + i * 2 + 1] = (guint8) (word_value & 0x00ff);
		pos += 5;
	}

	return TRUE;
}

Project: wireshark
File: toshiba.c

static gboolean toshiba_check_file_type(wtap *wth, int *err, gchar **err_info)
{
	char	buf[TOSHIBA_LINE_LENGTH];
	guint	i, reclen, level, line;
	char	byte;

	buf[TOSHIBA_LINE_LENGTH-1] = 0;

	for (line = 0; line < TOSHIBA_HEADER_LINES_TO_CHECK; line++) {
		if (file_gets(buf, TOSHIBA_LINE_LENGTH, wth->fh) == NULL) {
			/* EOF or error. */
			*err = file_error(wth->fh, err_info);
			return FALSE;
		}

		reclen = (guint) strlen(buf);
		if (reclen < TOSHIBA_HDR_MAGIC_SIZE) {
			continue;
		}

		level = 0;
		for (i = 0; i < reclen; i++) {
			byte = buf[i];
			if (byte == toshiba_hdr_magic[level]) {
				level++;
				if (level >= TOSHIBA_HDR_MAGIC_SIZE) {
					return TRUE;
				}
			}
			else {
				level = 0;
			}
		}
	}
	*err = 0;
	return FALSE;
}

Project: wireshark
File: toshiba.c

wtap_open_return_val toshiba_open(wtap *wth, int *err, gchar **err_info)
{
	/* Look for Toshiba header */
	if (!toshiba_check_file_type(wth, err, err_info)) {
		if (*err != 0 && *err != WTAP_ERR_SHORT_READ)
			return WTAP_OPEN_ERROR;
		return WTAP_OPEN_NOT_MINE;
	}

	wth->file_encap = WTAP_ENCAP_PER_PACKET;
	wth->file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_TOSHIBA;
	wth->snapshot_length = 0; /* not known */
	wth->subtype_read = toshiba_read;
	wth->subtype_seek_read = toshiba_seek_read;
	wth->file_tsprec = WTAP_TSPREC_CSEC;

	return WTAP_OPEN_MINE;
}

Project: wireshark
File: toshiba.c

static gboolean toshiba_read(wtap *wth, int *err, gchar **err_info,
    gint64 *data_offset)
{
	gint64	offset;

	/* Find the next packet */
	offset = toshiba_seek_next_packet(wth, err, err_info);
	if (offset < 1)
		return FALSE;
	*data_offset = offset;

	/* Parse the packet */
	return parse_toshiba_packet(wth->fh, &wth->phdr, wth->frame_buffer,
	    err, err_info);
}

Project: wireshark
File: toshiba.c

static gint64 toshiba_seek_next_packet(wtap *wth, int *err, gchar **err_info)
{
	int byte;
	guint level = 0;
	gint64 cur_off;

	while ((byte = file_getc(wth->fh)) != EOF) {
		if (byte == toshiba_rec_magic[level]) {
			level++;
			if (level >= TOSHIBA_REC_MAGIC_SIZE) {
				/* note: we're leaving file pointer right after the magic characters */
				cur_off = file_tell(wth->fh);
				if (cur_off == -1) {
					/* Error. */
					*err = file_error(wth->fh, err_info);
					return -1;
				}
				return cur_off + 1;
			}
		} else {
			level = 0;
		}
	}
	/* EOF or error. */
	*err = file_error(wth->fh, err_info);
	return -1;
}

Project: wireshark
File: toshiba.c

toshiba_seek_read(wtap *wth, gint64 seek_off,
	struct wtap_pkthdr *phdr, Buffer *buf,
	int *err, gchar **err_info)
{
	if (file_seek(wth->random_fh, seek_off - 1, SEEK_SET, err) == -1)
		return FALSE;

	if (!parse_toshiba_packet(wth->random_fh, phdr, buf, err, err_info)) {
		if (*err == 0)
			*err = WTAP_ERR_SHORT_READ;
		return FALSE;
	}
	return TRUE;
}