CVE-2017-12897 (C, published 2017-09-14T06:29Z)
Description: value: The ISO CLNS parser in tcpdump before 4.9.2 has a buffer over-read in print-isoclns.c:isoclns_print().
Severity: HIGH (CVSS v3 base score: 9.8)
Weakness: CWE-125 \u2014 Out-of-bounds Read
The product reads data past the end, or before the beginning, of the intended buffer.
Repository: https://github.com/the-tcpdump-group/tcpdump
Files changed:
netdissect.h
print-atm.c
print-chdlc.c
print-ether.c
print-fr.c
print-gre.c
print-isoclns.c
print-juniper.c
print-llc.c
print-mpls.c
print-null.c
print-ppp.c
tests/TESTLIST
tests/isoclns-oobr.out
Commit message: CVE-2017-12897/ISO CLNS: Use ND_TTEST() for the bounds checks in isoclns_print().

This fixes a buffer over-read discovered by Kamil Frankowicz.

Don't pass the remaining caplen - that's too hard to get right, and we
were getting it wrong in at least one case; just use ND_TTEST().

Add a test using the capture file supplied by the reporter(s).


Vulnerable code:
extern void isoclns_print(netdissect_options *, const u_char *, u_int, u_int);
            isoclns_print(ndo, p + 1, length - 1, caplen - 1);
                    isoclns_print(ndo, p + 1, length - 1, ndo->ndo_snapend - p - 1);
                    isoclns_print(ndo, p, length, ndo->ndo_snapend - p);
		isoclns_print(ndo, p + 1, length - 1, caplen - 1);
		isoclns_print(ndo, p - 1, length + 1, ndo->ndo_snapend - p + 1); /* OSI printers need the NLPID field */
		isoclns_print(ndo, bp, len, ndo->ndo_snapend - bp);
isoclns_print(netdissect_options *ndo,
              const uint8_t *p, u_int length, u_int caplen)
	if (caplen <= 1) { /* enough bytes on the wire ? */
			print_unknown_data(ndo, p, "\n\t", caplen);
			print_unknown_data(ndo, p, "\n\t", caplen);
		if (caplen > 1)
			print_unknown_data(ndo, p, "\n\t", caplen);
            isoclns_print(ndo, p, l2info.length, l2info.caplen);
                isoclns_print(ndo, p, l2info.length, l2info.caplen);
            isoclns_print(ndo, p + 1, l2info.length - 1, l2info.caplen - 1);
            isoclns_print(ndo, p - 1, l2info.length + 1, l2info.caplen + 1);
            isoclns_print(ndo, p, l2info.length, l2info.caplen);
            isoclns_print(ndo, p - 1, l2info.length + 1, l2info.caplen + 1);
            isoclns_print(ndo, p + 1, l2info.length - 1, l2info.caplen - 1);
            isoclns_print(ndo, p + 1, l2info.length - 1, l2info.caplen - 1);
		isoclns_print(ndo, p, length, caplen);
		isoclns_print(ndo, p, length, length);
		isoclns_print(ndo, p, length, caplen);
		isoclns_print(ndo, p, length, length);

Fixed code:
extern void isoclns_print(netdissect_options *, const u_char *, u_int);
            isoclns_print(ndo, p + 1, length - 1);
                    isoclns_print(ndo, p + 1, length - 1);
                    isoclns_print(ndo, p, length);
		isoclns_print(ndo, p + 1, length - 1);
		isoclns_print(ndo, p - 1, length + 1); /* OSI printers need the NLPID field */
		isoclns_print(ndo, bp, len);
isoclns_print(netdissect_options *ndo, const uint8_t *p, u_int length)
	if (!ND_TTEST(*p)) { /* enough bytes on the wire ? */
			print_unknown_data(ndo, p, "\n\t", length);
			print_unknown_data(ndo, p, "\n\t", length);
		if (length > 1)
			print_unknown_data(ndo, p, "\n\t", length);
            isoclns_print(ndo, p, l2info.length);
                isoclns_print(ndo, p, l2info.length);
            isoclns_print(ndo, p + 1, l2info.length - 1);
            isoclns_print(ndo, p - 1, l2info.length + 1);
            isoclns_print(ndo, p, l2info.length);
            isoclns_print(ndo, p - 1, l2info.length + 1);
            isoclns_print(ndo, p + 1, l2info.length - 1);
            isoclns_print(ndo, p + 1, l2info.length - 1);
		isoclns_print(ndo, p, length);
		isoclns_print(ndo, p, length);
		isoclns_print(ndo, p, length);
		isoclns_print(ndo, p, length);
isoclns-oobr		isoclns-oobr.pcap		isoclns-oobr.out
|OSI