Upgrade to tcpdump 4.9.2.

From CHANGES:

  Sunday September 3, 2017 denis@ovsienko.info
  Summary for 4.9.2 tcpdump release
    Do not use getprotobynumber() for protocol name resolution.  Do not do
      any protocol name resolution if -n is specified.
    Improve errors detection in the test scripts.
    Fix a segfault with OpenSSL 1.1 and improve OpenSSL usage.
    Clean up IS-IS printing.
    Fix buffer overflow vulnerabilities:
      CVE-2017-11543 (SLIP)
      CVE-2017-13011 (bittok2str_internal)
    Fix infinite loop vulnerabilities:
      CVE-2017-12989 (RESP)
      CVE-2017-12990 (ISAKMP)
      CVE-2017-12995 (DNS)
      CVE-2017-12997 (LLDP)
    Fix buffer over-read vulnerabilities:
      CVE-2017-11541 (safeputs)
      CVE-2017-11542 (PIMv1)
      CVE-2017-12893 (SMB/CIFS)
      CVE-2017-12894 (lookup_bytestring)
      CVE-2017-12895 (ICMP)
      CVE-2017-12896 (ISAKMP)
      CVE-2017-12897 (ISO CLNS)
      CVE-2017-12898 (NFS)
      CVE-2017-12899 (DECnet)
      CVE-2017-12900 (tok2strbuf)
      CVE-2017-12901 (EIGRP)
      CVE-2017-12902 (Zephyr)
      CVE-2017-12985 (IPv6)
      CVE-2017-12986 (IPv6 routing headers)
      CVE-2017-12987 (IEEE 802.11)
      CVE-2017-12988 (telnet)
      CVE-2017-12991 (BGP)
      CVE-2017-12992 (RIPng)
      CVE-2017-12993 (Juniper)
      CVE-2017-11542 (PIMv1)
      CVE-2017-11541 (safeputs)
      CVE-2017-12994 (BGP)
      CVE-2017-12996 (PIMv2)
      CVE-2017-12998 (ISO IS-IS)
      CVE-2017-12999 (ISO IS-IS)
      CVE-2017-13000 (IEEE 802.15.4)
      CVE-2017-13001 (NFS)
      CVE-2017-13002 (AODV)
      CVE-2017-13003 (LMP)
      CVE-2017-13004 (Juniper)
      CVE-2017-13005 (NFS)
      CVE-2017-13006 (L2TP)
      CVE-2017-13007 (Apple PKTAP)
      CVE-2017-13008 (IEEE 802.11)
      CVE-2017-13009 (IPv6 mobility)
      CVE-2017-13010 (BEEP)
      CVE-2017-13012 (ICMP)
      CVE-2017-13013 (ARP)
      CVE-2017-13014 (White Board)
      CVE-2017-13015 (EAP)
      CVE-2017-11543 (SLIP)
      CVE-2017-13016 (ISO ES-IS)
      CVE-2017-13017 (DHCPv6)
      CVE-2017-13018 (PGM)
      CVE-2017-13019 (PGM)
      CVE-2017-13020 (VTP)
      CVE-2017-13021 (ICMPv6)
      CVE-2017-13022 (IP)
      CVE-2017-13023 (IPv6 mobility)
      CVE-2017-13024 (IPv6 mobility)
      CVE-2017-13025 (IPv6 mobility)
      CVE-2017-13026 (ISO IS-IS)
      CVE-2017-13027 (LLDP)
      CVE-2017-13028 (BOOTP)
      CVE-2017-13029 (PPP)
      CVE-2017-13030 (PIM)
      CVE-2017-13031 (IPv6 fragmentation header)
      CVE-2017-13032 (RADIUS)
      CVE-2017-13033 (VTP)
      CVE-2017-13034 (PGM)
      CVE-2017-13035 (ISO IS-IS)
      CVE-2017-13036 (OSPFv3)
      CVE-2017-13037 (IP)
      CVE-2017-13038 (PPP)
      CVE-2017-13039 (ISAKMP)
      CVE-2017-13040 (MPTCP)
      CVE-2017-13041 (ICMPv6)
      CVE-2017-13042 (HNCP)
      CVE-2017-13043 (BGP)
      CVE-2017-13044 (HNCP)
      CVE-2017-13045 (VQP)
      CVE-2017-13046 (BGP)
      CVE-2017-13047 (ISO ES-IS)
      CVE-2017-13048 (RSVP)
      CVE-2017-13049 (Rx)
      CVE-2017-13050 (RPKI-Router)
      CVE-2017-13051 (RSVP)
      CVE-2017-13052 (CFM)
      CVE-2017-13053 (BGP)
      CVE-2017-13054 (LLDP)
      CVE-2017-13055 (ISO IS-IS)
      CVE-2017-13687 (Cisco HDLC)
      CVE-2017-13688 (OLSR)
      CVE-2017-13689 (IKEv1)
      CVE-2017-13690 (IKEv2)
      CVE-2017-13725 (IPv6 routing headers)

Bug: N/A
Test: ran manually
Change-Id: I6fbfa46046ee89d40d13024777e27623a23cb258
diff --git a/print-rpki-rtr.c b/print-rpki-rtr.c
index 77e29c7..8e4c73f 100644
--- a/print-rpki-rtr.c
+++ b/print-rpki-rtr.c
@@ -12,7 +12,7 @@
  * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  * FOR A PARTICULAR PURPOSE.
  *
- * Original code by Hannes Gredler (hannes@juniper.net)
+ * Original code by Hannes Gredler (hannes@gredler.at)
  */
 
 /* \summary: Resource Public Key Infrastructure (RPKI) to Router Protocol printer */
@@ -82,6 +82,9 @@
 typedef struct rpki_rtr_pdu_error_report_ {
     rpki_rtr_pdu pdu_header;
     u_char encapsulated_pdu_length[4]; /* Encapsulated PDU length */
+    /* Copy of Erroneous PDU (variable, optional) */
+    /* Length of Error Text (4 octets in network byte order) */
+    /* Arbitrary Text of Error Diagnostic Message (variable, optional) */
 } rpki_rtr_pdu_error_report;
 
 /*
@@ -171,17 +174,38 @@
 /*
  * Print a single PDU.
  */
-static int
-rpki_rtr_pdu_print (netdissect_options *ndo, const u_char *tptr, u_int indent)
+static u_int
+rpki_rtr_pdu_print (netdissect_options *ndo, const u_char *tptr, const u_int len,
+	const u_char recurse, const u_int indent)
 {
     const rpki_rtr_pdu *pdu_header;
     u_int pdu_type, pdu_len, hexdump;
     const u_char *msg;
 
+    /* Protocol Version */
+    ND_TCHECK_8BITS(tptr);
+    if (*tptr != 0) {
+	/* Skip the rest of the input buffer because even if this is
+	 * a well-formed PDU of a future RPKI-Router protocol version
+	 * followed by a well-formed PDU of RPKI-Router protocol
+	 * version 0, there is no way to know exactly how to skip the
+	 * current PDU.
+	 */
+	ND_PRINT((ndo, "%sRPKI-RTRv%u (unknown)", indent_string(8), *tptr));
+	return len;
+    }
+    if (len < sizeof(rpki_rtr_pdu)) {
+	ND_PRINT((ndo, "(%u bytes is too few to decode)", len));
+	goto invalid;
+    }
+    ND_TCHECK2(*tptr, sizeof(rpki_rtr_pdu));
     pdu_header = (const rpki_rtr_pdu *)tptr;
     pdu_type = pdu_header->pdu_type;
     pdu_len = EXTRACT_32BITS(pdu_header->length);
-    ND_TCHECK2(*tptr, pdu_len);
+    /* Do not check bounds with pdu_len yet, do it in the case blocks
+     * below to make it possible to decode at least the beginning of
+     * a truncated Error Report PDU or a truncated encapsulated PDU.
+     */
     hexdump = FALSE;
 
     ND_PRINT((ndo, "%sRPKI-RTRv%u, %s PDU (%u), length: %u",
@@ -189,6 +213,8 @@
 	   pdu_header->version,
 	   tok2str(rpki_rtr_pdu_values, "Unknown", pdu_type),
 	   pdu_type, pdu_len));
+    if (pdu_len < sizeof(rpki_rtr_pdu) || pdu_len > len)
+	goto invalid;
 
     switch (pdu_type) {
 
@@ -198,6 +224,9 @@
     case RPKI_RTR_SERIAL_NOTIFY_PDU:
     case RPKI_RTR_SERIAL_QUERY_PDU:
     case RPKI_RTR_END_OF_DATA_PDU:
+	if (pdu_len != sizeof(rpki_rtr_pdu) + 4)
+	    goto invalid;
+	ND_TCHECK2(*tptr, pdu_len);
         msg = (const u_char *)(pdu_header + 1);
 	ND_PRINT((ndo, "%sSession ID: 0x%04x, Serial: %u",
 	       indent_string(indent+2),
@@ -210,6 +239,9 @@
 	 */
     case RPKI_RTR_RESET_QUERY_PDU:
     case RPKI_RTR_CACHE_RESET_PDU:
+	if (pdu_len != sizeof(rpki_rtr_pdu))
+	    goto invalid;
+	/* no additional boundary to check */
 
 	/*
 	 * Zero payload PDUs.
@@ -217,6 +249,9 @@
 	break;
 
     case RPKI_RTR_CACHE_RESPONSE_PDU:
+	if (pdu_len != sizeof(rpki_rtr_pdu))
+	    goto invalid;
+	/* no additional boundary to check */
 	ND_PRINT((ndo, "%sSession ID: 0x%04x",
 	       indent_string(indent+2),
 	       EXTRACT_16BITS(pdu_header->u.session_id)));
@@ -226,6 +261,9 @@
 	{
 	    const rpki_rtr_pdu_ipv4_prefix *pdu;
 
+	    if (pdu_len != sizeof(rpki_rtr_pdu) + 12)
+		goto invalid;
+	    ND_TCHECK2(*tptr, pdu_len);
 	    pdu = (const rpki_rtr_pdu_ipv4_prefix *)tptr;
 	    ND_PRINT((ndo, "%sIPv4 Prefix %s/%u-%u, origin-as %u, flags 0x%02x",
 		   indent_string(indent+2),
@@ -239,6 +277,9 @@
 	{
 	    const rpki_rtr_pdu_ipv6_prefix *pdu;
 
+	    if (pdu_len != sizeof(rpki_rtr_pdu) + 24)
+		goto invalid;
+	    ND_TCHECK2(*tptr, pdu_len);
 	    pdu = (const rpki_rtr_pdu_ipv6_prefix *)tptr;
 	    ND_PRINT((ndo, "%sIPv6 Prefix %s/%u-%u, origin-as %u, flags 0x%02x",
 		   indent_string(indent+2),
@@ -253,10 +294,17 @@
 	    const rpki_rtr_pdu_error_report *pdu;
 	    u_int encapsulated_pdu_length, text_length, tlen, error_code;
 
+	    tlen = sizeof(rpki_rtr_pdu);
+	    /* Do not test for the "Length of Error Text" data element yet. */
+	    if (pdu_len < tlen + 4)
+		goto invalid;
+	    ND_TCHECK2(*tptr, tlen + 4);
+	    /* Safe up to and including the "Length of Encapsulated PDU"
+	     * data element, more data elements may be present.
+	     */
 	    pdu = (const rpki_rtr_pdu_error_report *)tptr;
 	    encapsulated_pdu_length = EXTRACT_32BITS(pdu->encapsulated_pdu_length);
-	    ND_TCHECK2(*tptr, encapsulated_pdu_length);
-	    tlen = pdu_len;
+	    tlen += 4;
 
 	    error_code = EXTRACT_16BITS(pdu->pdu_header.u.error_code);
 	    ND_PRINT((ndo, "%sError code: %s (%u), Encapsulated PDU length: %u",
@@ -264,41 +312,58 @@
 		   tok2str(rpki_rtr_error_codes, "Unknown", error_code),
 		   error_code, encapsulated_pdu_length));
 
-	    tptr += sizeof(*pdu);
-	    tlen -= sizeof(*pdu);
-
-	    /*
-	     * Recurse if there is an encapsulated PDU.
-	     */
-	    if (encapsulated_pdu_length &&
-		(encapsulated_pdu_length <= tlen)) {
-		ND_PRINT((ndo, "%s-----encapsulated PDU-----", indent_string(indent+4)));
-		if (rpki_rtr_pdu_print(ndo, tptr, indent+2))
-			goto trunc;
+	    if (encapsulated_pdu_length) {
+		/* Section 5.10 of RFC 6810 says:
+		 * "An Error Report PDU MUST NOT be sent for an Error Report PDU."
+		 *
+		 * However, as far as the protocol encoding goes Error Report PDUs can
+		 * happen to be nested in each other, however many times, in which case
+		 * the decoder should still print such semantically incorrect PDUs.
+		 *
+		 * That said, "the Erroneous PDU field MAY be truncated" (ibid), thus
+		 * to keep things simple this implementation decodes only the two
+		 * outermost layers of PDUs and makes bounds checks in the outer and
+		 * the inner PDU independently.
+		 */
+		if (pdu_len < tlen + encapsulated_pdu_length)
+		    goto invalid;
+		if (! recurse) {
+		    ND_TCHECK2(*tptr, tlen + encapsulated_pdu_length);
+		}
+		else {
+		    ND_PRINT((ndo, "%s-----encapsulated PDU-----", indent_string(indent+4)));
+		    rpki_rtr_pdu_print(ndo, tptr + tlen,
+			encapsulated_pdu_length, 0, indent + 2);
+		}
+		tlen += encapsulated_pdu_length;
 	    }
 
-	    tptr += encapsulated_pdu_length;
-	    tlen -= encapsulated_pdu_length;
+	    if (pdu_len < tlen + 4)
+		goto invalid;
+	    ND_TCHECK2(*tptr, tlen + 4);
+	    /* Safe up to and including the "Length of Error Text" data element,
+	     * one more data element may be present.
+	     */
 
 	    /*
 	     * Extract, trail-zero and print the Error message.
 	     */
-	    text_length = 0;
-	    if (tlen > 4) {
-		text_length = EXTRACT_32BITS(tptr);
-		tptr += 4;
-		tlen -= 4;
-	    }
-	    ND_TCHECK2(*tptr, text_length);
-	    if (text_length && (text_length <= tlen )) {
+	    text_length = EXTRACT_32BITS(tptr + tlen);
+	    tlen += 4;
+
+	    if (text_length) {
+		if (pdu_len < tlen + text_length)
+		    goto invalid;
+		/* fn_printn() makes the bounds check */
 		ND_PRINT((ndo, "%sError text: ", indent_string(indent+2)));
-		if (fn_printn(ndo, tptr, text_length, ndo->ndo_snapend))
+		if (fn_printn(ndo, tptr + tlen, text_length, ndo->ndo_snapend))
 			goto trunc;
 	    }
 	}
 	break;
 
     default:
+	ND_TCHECK2(*tptr, pdu_len);
 
 	/*
 	 * Unknown data, please hexdump.
@@ -310,57 +375,29 @@
     if (ndo->ndo_vflag > 1 || (ndo->ndo_vflag && hexdump)) {
 	print_unknown_data(ndo,tptr,"\n\t  ", pdu_len);
     }
-    return 0;
+    return pdu_len;
 
+invalid:
+    ND_PRINT((ndo, "%s", istr));
+    ND_TCHECK2(*tptr, len);
+    return len;
 trunc:
-    return 1;
+    ND_PRINT((ndo, "\n\t%s", tstr));
+    return len;
 }
 
 void
 rpki_rtr_print(netdissect_options *ndo, register const u_char *pptr, register u_int len)
 {
-    u_int tlen, pdu_type, pdu_len;
-    const u_char *tptr;
-    const rpki_rtr_pdu *pdu_header;
-
-    tptr = pptr;
-    tlen = len;
-
     if (!ndo->ndo_vflag) {
 	ND_PRINT((ndo, ", RPKI-RTR"));
 	return;
     }
-
-    while (tlen >= sizeof(rpki_rtr_pdu)) {
-
-        ND_TCHECK2(*tptr, sizeof(rpki_rtr_pdu));
-
-	pdu_header = (const rpki_rtr_pdu *)tptr;
-        pdu_type = pdu_header->pdu_type;
-        pdu_len = EXTRACT_32BITS(pdu_header->length);
-        ND_TCHECK2(*tptr, pdu_len);
-
-        /* infinite loop check */
-        if (!pdu_type || !pdu_len) {
-            break;
-        }
-
-        if (tlen < pdu_len) {
-            goto trunc;
-        }
-
-	/*
-	 * Print the PDU.
-	 */
-	if (rpki_rtr_pdu_print(ndo, tptr, 8))
-		goto trunc;
-
-        tlen -= pdu_len;
-        tptr += pdu_len;
+    while (len) {
+	u_int pdu_len = rpki_rtr_pdu_print(ndo, pptr, len, 1, 8);
+	len -= pdu_len;
+	pptr += pdu_len;
     }
-    return;
-trunc:
-    ND_PRINT((ndo, "\n\t%s", tstr));
 }
 
 /*