From 1dcd10aceabbc03bf571ea32b892c522cbe923de Mon Sep 17 00:00:00 2001
From: Guy Harris <guy@alum.mit.edu>
Date: Fri, 3 Feb 2017 12:24:14 -0800
Subject: [PATCH] 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).
---
 netdissect.h            |   2 +-
 print-atm.c             |   2 +-
 print-chdlc.c           |   4 ++--
 print-ether.c           |   2 +-
 print-fr.c              |   2 +-
 print-gre.c             |   2 +-
 print-isoclns.c         |  13 ++++++-------
 print-juniper.c         |  16 ++++++++--------
 print-llc.c             |   2 +-
 print-mpls.c            |   2 +-
 print-null.c            |   2 +-
 print-ppp.c             |   2 +-
 tests/TESTLIST          |   1 +
 tests/isoclns-oobr.out  |   1 +
 tests/isoclns-oobr.pcap | Bin 0 -> 88 bytes
 15 files changed, 27 insertions(+), 26 deletions(-)
 create mode 100644 tests/isoclns-oobr.out
 create mode 100644 tests/isoclns-oobr.pcap

Index: tcpdump-3.9.8/netdissect.h
===================================================================
--- tcpdump-3.9.8.orig/netdissect.h
+++ tcpdump-3.9.8/netdissect.h
@@ -313,8 +313,7 @@ extern void igrp_print(netdissect_option
 		       const u_char *);
 extern void ipN_print(netdissect_options *,const u_char *, u_int);
 extern void ipx_print(netdissect_options *,const u_char *, u_int);
-extern void isoclns_print(netdissect_options *,const u_char *,
-			  u_int, u_int, const u_char *,	const u_char *);
+extern void isoclns_print(const u_char *, u_int);
 extern void krb_print(netdissect_options *,const u_char *, u_int);
 extern void llap_print(netdissect_options *,const u_char *, u_int);
 extern const char *linkaddr_string(netdissect_options *ndo,
Index: tcpdump-3.9.8/print-atm.c
===================================================================
--- tcpdump-3.9.8.orig/print-atm.c
+++ tcpdump-3.9.8/print-atm.c
@@ -146,7 +146,7 @@ atm_if_print(const struct pcap_pkthdr *h
         if (*p == LLC_UI) {
             if (eflag)
                 printf("CNLPID ");
-            isoclns_print(p+1, length-1, caplen-1);
+            isoclns_print(p+1, length-1);
             return hdrlen;
         }
 
Index: tcpdump-3.9.8/print-chdlc.c
===================================================================
--- tcpdump-3.9.8.orig/print-chdlc.c
+++ tcpdump-3.9.8/print-chdlc.c
@@ -105,9 +105,9 @@ chdlc_print(register const u_char *p, u_
                 if (*(p+1) == 0x81 ||
                     *(p+1) == 0x82 ||
                     *(p+1) == 0x83)
-                    isoclns_print(p+1, length-1, length-1);
+                    isoclns_print(p+1, length-1);
                 else
-                    isoclns_print(p, length, length);
+                    isoclns_print(p, length);
                 break;
 	default:
                 if (!eflag)
Index: tcpdump-3.9.8/print-ether.c
===================================================================
--- tcpdump-3.9.8.orig/print-ether.c
+++ tcpdump-3.9.8/print-ether.c
@@ -284,7 +284,7 @@ ether_encap_print(u_short ether_type, co
 			printf(" [|osi]");
 			return (1);
 		}
-		isoclns_print(p + 1, length - 1, caplen - 1);
+		isoclns_print(p + 1, length - 1);
                 return(1);
 
 	case ETHERTYPE_PPPOED:
Index: tcpdump-3.9.8/print-fr.c
===================================================================
--- tcpdump-3.9.8.orig/print-fr.c
+++ tcpdump-3.9.8/print-fr.c
@@ -282,7 +282,7 @@ fr_print(register const u_char *p, u_int
 	case NLPID_CLNP:
 	case NLPID_ESIS:
 	case NLPID_ISIS:
-                isoclns_print(p-1, length+1, length+1); /* OSI printers need the NLPID field */
+                isoclns_print(p-1, length+1); /* OSI printers need the NLPID field */
 		break;
 
 	case NLPID_SNAP:
Index: tcpdump-3.9.8/print-gre.c
===================================================================
--- tcpdump-3.9.8.orig/print-gre.c
+++ tcpdump-3.9.8/print-gre.c
@@ -232,7 +232,7 @@ gre_print_0(const u_char *bp, u_int leng
 		atalk_print(bp, len);
 		break;
 	case ETHERTYPE_GRE_ISO:
-		isoclns_print(bp, len, len);
+		isoclns_print(bp, len);
 		break;
 	default:
 		printf("gre-proto-0x%x", prot);
Index: tcpdump-3.9.8/print-isoclns.c
===================================================================
--- tcpdump-3.9.8.orig/print-isoclns.c
+++ tcpdump-3.9.8/print-isoclns.c
@@ -666,13 +666,13 @@ create_osi_cksum (const u_int8_t *pptr,
     return checksum;
 }
 
-void isoclns_print(const u_int8_t *p, u_int length, u_int caplen)
+void isoclns_print(const u_int8_t *p, u_int length)
 {
 	const struct isis_common_header *header;
 
 	header = (const struct isis_common_header *)p;
 
-        if (caplen <= 1) { /* enough bytes on the wire ? */
+	if (!TTEST(*p)) { /* enough bytes on the wire ? */
             printf("|OSI");
             return;
         }
@@ -686,7 +686,7 @@ void isoclns_print(const u_int8_t *p, u_
 
 	case NLPID_CLNP:
 		if (!clnp_print(p, length))
-                        print_unknown_data(p,"\n\t",caplen);
+                        print_unknown_data(p,"\n\t",length);
 		break;
 
 	case NLPID_ESIS:
@@ -695,7 +695,7 @@ void isoclns_print(const u_int8_t *p, u_
 
 	case NLPID_ISIS:
 		if (!isis_print(p, length))
-                        print_unknown_data(p,"\n\t",caplen);
+                        print_unknown_data(p,"\n\t",length);
 		break;
 
 	case NLPID_NULLNS:
@@ -728,8 +728,8 @@ void isoclns_print(const u_int8_t *p, u_
 		(void)printf("%slength: %u",
 		             eflag ? "" : ", ",
                              length);
-		if (caplen > 1)
-                        print_unknown_data(p,"\n\t",caplen);
+		if (length > 1)
+                        print_unknown_data(p,"\n\t",length);
 		break;
 	}
 }
Index: tcpdump-3.9.8/print-juniper.c
===================================================================
--- tcpdump-3.9.8.orig/print-juniper.c
+++ tcpdump-3.9.8/print-juniper.c
@@ -493,7 +493,7 @@ juniper_mlppp_print(const struct pcap_pk
             mpls_print(p,l2info.length);
             return l2info.header_len;
         case JUNIPER_LSQ_L3_PROTO_ISO:
-            isoclns_print(p,l2info.length,l2info.caplen);
+            isoclns_print(p,l2info.length);
             return l2info.header_len;
         default:
             break;
@@ -548,7 +548,7 @@ juniper_mfr_print(const struct pcap_pkth
                 mpls_print(p,l2info.length);
                 return l2info.header_len;
             case JUNIPER_LSQ_L3_PROTO_ISO:
-                isoclns_print(p,l2info.length,l2info.caplen);
+                isoclns_print(p,l2info.length);
                 return l2info.header_len;
             default:
                 break;
@@ -560,13 +560,13 @@ juniper_mfr_print(const struct pcap_pkth
         if (eflag && EXTRACT_32BITS(l2info.cookie) != 1) printf("Bundle-ID %u, ",l2info.bundle);
         switch (l2info.proto) {
         case (LLCSAP_ISONS<<8 | LLCSAP_ISONS):
-            isoclns_print(p+1, l2info.length-1, l2info.caplen-1);
+            isoclns_print(p+1, l2info.length-1);
             break;
         case (LLC_UI<<8 | NLPID_Q933):
         case (LLC_UI<<8 | NLPID_IP):
         case (LLC_UI<<8 | NLPID_IP6):
             /* pass IP{4,6} to the OSI layer for proper link-layer printing */
-            isoclns_print(p-1, l2info.length+1, l2info.caplen+1); 
+            isoclns_print(p-1, l2info.length+1);
             break;
         default:
             printf("unknown protocol 0x%04x, length %u",l2info.proto, l2info.length);
@@ -593,13 +593,13 @@ juniper_mlfr_print(const struct pcap_pkt
         switch (l2info.proto) {
         case (LLC_UI):
         case (LLC_UI<<8):
-            isoclns_print(p, l2info.length, l2info.caplen);
+            isoclns_print(p, l2info.length);
             break;
         case (LLC_UI<<8 | NLPID_Q933):
         case (LLC_UI<<8 | NLPID_IP):
         case (LLC_UI<<8 | NLPID_IP6):
             /* pass IP{4,6} to the OSI layer for proper link-layer printing */
-            isoclns_print(p-1, l2info.length+1, l2info.caplen+1);
+            isoclns_print(p-1, l2info.length+1);
             break;
         default:
             printf("unknown protocol 0x%04x, length %u",l2info.proto, l2info.length);
@@ -645,7 +645,7 @@ juniper_atm1_print(const struct pcap_pkt
         }
 
         if (p[0] == 0x03) { /* Cisco style NLPID encaps ? */
-            isoclns_print(p + 1, l2info.length - 1, l2info.caplen - 1);
+            isoclns_print(p + 1, l2info.length - 1);
             /* FIXME check if frame was recognized */
             return l2info.header_len;
         }
@@ -699,7 +699,7 @@ juniper_atm2_print(const struct pcap_pkt
         }
 
         if (p[0] == 0x03) { /* Cisco style NLPID encaps ? */
-            isoclns_print(p + 1, l2info.length - 1, l2info.caplen - 1);
+            isoclns_print(p + 1, l2info.length - 1);
             /* FIXME check if frame was recognized */
             return l2info.header_len;
         }
Index: tcpdump-3.9.8/print-llc.c
===================================================================
--- tcpdump-3.9.8.orig/print-llc.c
+++ tcpdump-3.9.8/print-llc.c
@@ -296,7 +296,7 @@ llc_print(const u_char *p, u_int length,
 #endif
 	if (ssap == LLCSAP_ISONS && dsap == LLCSAP_ISONS
 	    && control == LLC_UI) {
-		isoclns_print(p + 3, length - 3, caplen - 3);
+		isoclns_print(p + 3, length - 3);
 		return (1);
 	}
 
Index: tcpdump-3.9.8/print-mpls.c
===================================================================
--- tcpdump-3.9.8.orig/print-mpls.c
+++ tcpdump-3.9.8/print-mpls.c
@@ -170,7 +170,7 @@ mpls_print(const u_char *bp, u_int lengt
                     case 0x83:
 		        if (vflag>0) {
                             printf("\n\t");
-                            isoclns_print(p, length - (p - bp), length - (p - bp));
+                            isoclns_print(p, length - (p - bp));
 			    }
 			else printf(", OSI, length: %u",length);
                         break;
Index: tcpdump-3.9.8/print-null.c
===================================================================
--- tcpdump-3.9.8.orig/print-null.c
+++ tcpdump-3.9.8/print-null.c
@@ -131,7 +131,7 @@ null_if_print(const struct pcap_pkthdr *
 #endif
 
 	case BSD_AFNUM_ISO:
-		isoclns_print(p, length, caplen);
+		isoclns_print(p, length);
 		break;
 
 	case BSD_AFNUM_APPLETALK:
Index: tcpdump-3.9.8/print-ppp.c
===================================================================
--- tcpdump-3.9.8.orig/print-ppp.c
+++ tcpdump-3.9.8/print-ppp.c
@@ -1379,7 +1379,7 @@ handle_ppp(u_int proto, const u_char *p,
 		ipx_print(p, length);
 		break;
 	case PPP_OSI:
-	        isoclns_print(p, length, length);
+	        isoclns_print(p, length);
 	        break;
 	case PPP_MPLS_UCAST:
 	case PPP_MPLS_MCAST:
Index: tcpdump-3.9.8/interface.h
===================================================================
--- tcpdump-3.9.8.orig/interface.h
+++ tcpdump-3.9.8/interface.h
@@ -223,7 +223,7 @@ extern void igrp_print(const u_char *, u
 extern void ipN_print(const u_char *, u_int);
 extern u_int ipfc_if_print(const struct pcap_pkthdr *, const u_char *);
 extern void ipx_print(const u_char *, u_int);
-extern void isoclns_print(const u_char *, u_int, u_int);
+extern void isoclns_print(const u_char *, u_int);
 extern void krb_print(const u_char *);
 extern u_int llap_print(const u_char *, u_int);
 extern u_int ltalk_if_print(const struct pcap_pkthdr *, const u_char *);
