Commit message: CVE-2017-12894/In lookup_bytestring(), take the length of the byte string into account.

Otherwise, if, in our search of the hash table, we come across a byte
string that's shorter than the string we're looking for, we'll search
past the end of the string in the hash table.

This fixes a buffer over-read discovered by Forcepoint's security
researchers Otto Airamo & Antti Levomäki.

Add a test using the capture file supplied by the reporter(s).
CVE: CVE-2017-12894
CWE: CWE-125
Vulnerability description: Several protocol parsers in tcpdump before 4.9.2 could cause a buffer over-read in addrtoname.c:lookup_bytestring().

Project: tcpdump
File: addrtoname.c

le64addr_string(netdissect_options *ndo, const u_char *ep)
{
 	const unsigned int len = 8;
 	register u_int i;
 	register char *cp;
	register struct bsnamemem *tp;
 	char buf[BUFSIZE];
 
 	tp = lookup_bytestring(ndo, ep, len);
	if (tp->bs_name)
		return (tp->bs_name);
 
 	cp = buf;
 	for (i = len; i > 0 ; --i) {
		*cp++ = hex[*(ep + i - 1) >> 4];
		*cp++ = hex[*(ep + i - 1) & 0xf];
		*cp++ = ':';
	}
	cp --;
 
 	*cp = '\0';
 
	tp->bs_name = strdup(buf);
	if (tp->bs_name == NULL)
 		(*ndo->ndo_error)(ndo, "le64addr_string: strdup(buf)");
 
	return (tp->bs_name);
 }

Project: tcpdump
File: addrtoname.c

linkaddr_string(netdissect_options *ndo, const u_char *ep,
		const unsigned int type, const unsigned int len)
 {
 	register u_int i;
 	register char *cp;
	register struct bsnamemem *tp;
 
 	if (len == 0)
 		return ("<empty>");

	if (type == LINKADDR_ETHER && len == ETHER_ADDR_LEN)
		return (etheraddr_string(ndo, ep));

	if (type == LINKADDR_FRELAY)
 		return (q922_string(ndo, ep, len));
 
 	tp = lookup_bytestring(ndo, ep, len);
	if (tp->bs_name)
		return (tp->bs_name);
 
	tp->bs_name = cp = (char *)malloc(len*3);
	if (tp->bs_name == NULL)
 		(*ndo->ndo_error)(ndo, "linkaddr_string: malloc");
 	*cp++ = hex[*ep >> 4];
 	*cp++ = hex[*ep++ & 0xf];
	for (i = len-1; i > 0 ; --i) {
		*cp++ = ':';
		*cp++ = hex[*ep >> 4];
 		*cp++ = hex[*ep++ & 0xf];
 	}
 	*cp = '\0';
	return (tp->bs_name);
 }

Project: tcpdump
File: addrtoname.c

 lookup_bytestring(netdissect_options *ndo, register const u_char *bs,
 		  const unsigned int nlen)
 {
	struct bsnamemem *tp;
 	register u_int i, j, k;
 
 	if (nlen >= 6) {
		k = (bs[0] << 8) | bs[1];
		j = (bs[2] << 8) | bs[3];
		i = (bs[4] << 8) | bs[5];
	} else if (nlen >= 4) {
		k = (bs[0] << 8) | bs[1];
		j = (bs[2] << 8) | bs[3];
		i = 0;
	} else
 		i = j = k = 0;
 
 	tp = &bytestringtable[(i ^ j) & (HASHNAMESIZE-1)];
	while (tp->bs_nxt)
		if (nlen == tp->bs_nbytes &&
		    tp->bs_addr0 == i &&
		    tp->bs_addr1 == j &&
		    tp->bs_addr2 == k &&
		    memcmp((const char *)bs, (const char *)(tp->bs_bytes), nlen) == 0)
 			return tp;
 		else
			tp = tp->bs_nxt;
 
	tp->bs_addr0 = i;
	tp->bs_addr1 = j;
	tp->bs_addr2 = k;
 
	tp->bs_bytes = (u_char *) calloc(1, nlen + 1);
	if (tp->bs_bytes == NULL)
 		(*ndo->ndo_error)(ndo, "lookup_bytestring: calloc");
 
	memcpy(tp->bs_bytes, bs, nlen);
	tp->bs_nbytes = nlen;
	tp->bs_nxt = (struct bsnamemem *)calloc(1, sizeof(*tp));
	if (tp->bs_nxt == NULL)
 		(*ndo->ndo_error)(ndo, "lookup_bytestring: calloc");
 
 	return tp;
}