CVE-2017-12986: Out-of-bounds Read (CWE-125)
value: The IPv6 routing header parser in tcpdump before 4.9.2 has a buffer over-read in print-rt6.c:rt6_print().
CWE description: The product reads data past the end, or before the beginning, of the intended buffer.
CVSS v3 base score: 9.8
Published: 2017-09-14T06:29Z
Repository: https://github.com/the-tcpdump-group/tcpdump
Language: C
Files changed: ip6.h, tests/TESTLIST, tests/ipv6-rthdr-oobr.out
Commit date: 2017-09-13 12:25:44 +0100
Commit message: CVE-2017-12986/IPv6 R.H.: Update to reflect the actual IPv6 RFC.

In RFC 1883, the Type 0 routing header had a 1-byte reserved field and a
3-byte strict/loose bit map; in RFC 2460, that changed to a 4-byte
reserved field.

This fixes a buffer over-read discovered by Brian 'geeknik' Carpenter (by
making an ND_TCHECK() call check for the presence in the captured data
of all 4 bytes of the reserved field; we were printing it as a 4-byte
field, so we needed to check for them).

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

Diff: diff --git a/ip6.h b/ip6.h
index 2ea1d0abe..986203414 100644
--- a/ip6.h
+++ b/ip6.h
@@ -179,13 +179,12 @@ struct ip6_rthdr {
 /* Also used for Type 2 */
 struct ip6_rthdr0 {
 	uint8_t  ip6r0_nxt;		/* next header */
 	uint8_t  ip6r0_len;		/* length in units of 8 octets */
 	uint8_t  ip6r0_type;		/* always zero */
-	uint8_t  ip6r0_segleft;	/* segments left */
-	uint8_t  ip6r0_reserved;	/* reserved field */
-	uint8_t  ip6r0_slmap[3];	/* strict/loose bit map */
+	uint8_t  ip6r0_segleft;		/* segments left */
+	uint32_t ip6r0_reserved;	/* reserved field */
 	struct in6_addr ip6r0_addr[1];	/* up to 23 addresses */
 } UNALIGNED;
 
 /* Fragment header */
 struct ip6_frag {
diff --git a/tests/TESTLIST b/tests/TESTLIST
index 9b60df27b..6d6f41b75 100644
--- a/tests/TESTLIST
+++ b/tests/TESTLIST
@@ -432,10 +432,11 @@ otv-heapoverflow-1	otv-heapoverflow-1.pcap		otv-heapoverflow-1.out		-c10
 otv-heapoverflow-2	otv-heapoverflow-2.pcap		otv-heapoverflow-2.out		-c10
 q933-heapoverflow-2	q933-heapoverflow-2.pcap	q933-heapoverflow-2.out
 atm-heapoverflow	atm-heapoverflow.pcap		atm-heapoverflow.out		-c1 -e
 ipv6-next-header-oobr-1	ipv6-next-header-oobr-1.pcap	ipv6-next-header-oobr-1.out
 ipv6-next-header-oobr-2	ipv6-next-header-oobr-2.pcap	ipv6-next-header-oobr-2.out
+ipv6-rthdr-oobr		ipv6-rthdr-oobr.pcap		ipv6-rthdr-oobr.out
 
 # bad packets from Kamil Frankowicz
 snmp-heapoverflow-1	snmp-heapoverflow-1.pcap	snmp-heapoverflow-1.out
 snmp-heapoverflow-2	snmp-heapoverflow-2.pcap	snmp-heapoverflow-2.out
 isoclns-heapoverflow-2	isoclns-heapoverflow-2.pcap	isoclns-heapoverflow-2.out	-e -c1
diff --git a/tests/ipv6-rthdr-oobr.out b/tests/ipv6-rthdr-oobr.out
new file mode 100644
index 000000000..05824e40c
--- /dev/null
+++ b/tests/ipv6-rthdr-oobr.out
@@ -0,0 +1 @@
+IP6 3030:3030:3030:3030:3030:3030:3030:3030 > 3030:3030:3030:3030:3030:3030:3030:3030: srcrt (len=48, type=0, segleft=48[|srcrt]
diff --git a/tests/ipv6-rthdr-oobr.pcap b/tests/ipv6-rthdr-oobr.pcap
new file mode 100644
index 000000000..41f96b6d6
Binary files /dev/null and b/tests/ipv6-rthdr-oobr.pcap differ

Vulnerable code: 	uint8_t  ip6r0_segleft;	/* segments left */
	uint8_t  ip6r0_reserved;	/* reserved field */
	uint8_t  ip6r0_slmap[3];	/* strict/loose bit map */
Fixed code: 	uint8_t  ip6r0_segleft;		/* segments left */
	uint32_t ip6r0_reserved;	/* reserved field */
ipv6-rthdr-oobr		ipv6-rthdr-oobr.pcap		ipv6-rthdr-oobr.out
IP6 3030:3030:3030:3030:3030:3030:3030:3030 > 3030:3030:3030:3030:3030:3030:3030:3030: srcrt (len=48, type=0, segleft=48[|srcrt]