From 4038f83ebf654804829b258dde5e0a508c1c2003 Mon Sep 17 00:00:00 2001
From: Guy Harris <guy@alum.mit.edu>
Date: Tue, 11 Nov 2014 16:49:39 -0800
Subject: [PATCH 2/3] Do more bounds checking and length checking.

Don't run past the end of the captured data, and don't run past the end
of the packet (i.e., don't make the length variable go negative).

Also, stop dissecting if the message length isn't valid.
---
 print-olsr.c | 56 +++++++++++++++++++++++++++++++++++++++++++-------------
 1 file changed, 43 insertions(+), 13 deletions(-)

Index: tcpdump-3.9.8/print-olsr.c
===================================================================
--- tcpdump-3.9.8.orig/print-olsr.c	2014-12-11 17:58:11.589537227 +0100
+++ tcpdump-3.9.8/print-olsr.c	2014-12-11 18:46:59.860738841 +0100
@@ -157,14 +157,16 @@ struct olsr_lq_neighbor {
 /*
  * print a neighbor list with LQ extensions.
  */
-static void
-olsr_print_lq_neighbor (const u_char *msg_data, u_int hello_len)
+static int
+olsr_print_lq_neighbor (netdissect_options *ndo, const u_char *msg_data, u_int hello_len)
 {
     struct olsr_lq_neighbor *lq_neighbor;
 
     while (hello_len >= sizeof(struct olsr_lq_neighbor)) {
 
         lq_neighbor = (struct olsr_lq_neighbor *)msg_data;
+        if (!ND_TTEST(*lq_neighbor))
+            return (-1);
 
         printf("\n\t      neighbor %s, link-quality %.2lf%%"
                ", neighbor-link-quality %.2lf%%",
@@ -175,13 +177,14 @@ olsr_print_lq_neighbor (const u_char *ms
         msg_data += sizeof(struct olsr_lq_neighbor);
         hello_len -= sizeof(struct olsr_lq_neighbor);
     }
+    return (0);
 }
 
 /*
  * print a neighbor list.
  */
-static void
-olsr_print_neighbor (const u_char *msg_data, u_int hello_len)
+static int
+olsr_print_neighbor (netdissect_options *ndo, const u_char *msg_data, u_int hello_len)
 {
     int neighbor;
 
@@ -190,6 +193,8 @@ olsr_print_neighbor (const u_char *msg_d
 
     while (hello_len >= sizeof(struct in_addr)) {
 
+        if (!ND_TTEST2(*msg_data, sizeof(struct in_addr)))
+            return (-1);
         /* print 4 neighbors per line */
 
         printf("%s%s", ipaddr_string(msg_data),
@@ -198,11 +203,12 @@ olsr_print_neighbor (const u_char *msg_d
         msg_data += sizeof(struct in_addr);
         hello_len -= sizeof(struct in_addr);
     }
+    return 0;
 }
 
 
 void
-olsr_print (const u_char *pptr, u_int length)
+olsr_print (netdissect_options *ndo, const u_char *pptr, u_int length)
 {
     union {
         const struct olsr_common *common;
@@ -245,6 +251,7 @@ olsr_print (const u_char *pptr, u_int le
     }
 
     while (tptr < (pptr+length)) {
+        int msg_len_valid = 0;
 
         if (!TTEST2(*tptr, sizeof(struct olsr_msg)))	
             goto trunc;
@@ -254,6 +261,10 @@ olsr_print (const u_char *pptr, u_int le
         msg_type = ptr.msg->msg_type;
         msg_len = EXTRACT_16BITS(ptr.msg->msg_len);
 
+        if ((msg_len >= sizeof (struct olsr_msg))
+               && (msg_len <= length))
+            msg_len_valid = 1;
+
         /* infinite loop check */
         if (msg_type == 0 || msg_len == 0) {
             return;
@@ -269,12 +280,18 @@ olsr_print (const u_char *pptr, u_int le
                EXTRACT_16BITS(ptr.msg->msg_seq),
                msg_len);
 
+        if (!msg_len_valid) {
+            return;
+        }
+
         msg_tlen = msg_len - sizeof(struct olsr_msg);
         msg_data = tptr + sizeof(struct olsr_msg);
 
         switch (msg_type) {
         case OLSR_HELLO_MSG:
         case OLSR_HELLO_LQ_MSG:
+            if (msg_tlen < sizeof(struct olsr_hello))
+                goto trunc;
             if (!TTEST2(*msg_data, sizeof(struct olsr_hello)))	
                 goto trunc;
 
@@ -307,10 +324,12 @@ olsr_print (const u_char *pptr, u_int le
                 msg_tlen -= sizeof(struct olsr_hello_link);
                 hello_len -= sizeof(struct olsr_hello_link);
 
+                if (!TTEST2(*msg_data, hello_len))
+                    goto trunc;
                 if (msg_type == OLSR_HELLO_MSG) {
-                    olsr_print_neighbor(msg_data, hello_len);
+                    olsr_print_neighbor(ndo, msg_data, hello_len);
                 } else {
-                    olsr_print_lq_neighbor(msg_data, hello_len);
+                    olsr_print_lq_neighbor(ndo, msg_data, hello_len);
                 }
 
                 msg_data += hello_len;
@@ -320,6 +339,8 @@ olsr_print (const u_char *pptr, u_int le
 
         case OLSR_TC_MSG:
         case OLSR_TC_LQ_MSG:
+            if (msg_tlen < sizeof(struct olsr_tc))
+                goto trunc;
             if (!TTEST2(*msg_data, sizeof(struct olsr_tc)))	
                 goto trunc;
 
@@ -330,9 +351,9 @@ olsr_print (const u_char *pptr, u_int le
             msg_tlen -= sizeof(struct olsr_tc);
 
             if (msg_type == OLSR_TC_MSG) {
-                olsr_print_neighbor(msg_data, msg_tlen);
+                olsr_print_neighbor(ndo, msg_data, msg_tlen);
             } else {
-                olsr_print_lq_neighbor(msg_data, msg_tlen);
+                olsr_print_lq_neighbor(ndo, msg_data, msg_tlen);
             }
             break;
 
Index: tcpdump-3.9.8/interface.h
===================================================================
--- tcpdump-3.9.8.orig/interface.h	2014-12-11 17:58:11.590537239 +0100
+++ tcpdump-3.9.8/interface.h	2014-12-11 17:59:43.637647080 +0100
@@ -167,6 +167,7 @@ extern const char *dnnum_string(u_short)
 /* The printer routines. */
 
 #include <pcap.h>
+#include "netdissect.h"
 
 extern int print_unknown_data(const u_char *, const char *,int);
 extern void ascii_print(const u_char *, u_int);
@@ -231,7 +232,7 @@ extern void ns_print(const u_char *, u_i
 extern void ntp_print(const u_char *, u_int);
 extern u_int null_if_print(const struct pcap_pkthdr *, const u_char *);
 extern void ospf_print(const u_char *, u_int, const u_char *);
-extern void olsr_print (const u_char *, u_int);
+extern void olsr_print (netdissect_options *, const u_char *, u_int);
 extern void pimv1_print(const u_char *, u_int);
 extern void cisco_autorp_print(const u_char *, u_int);
 extern void rsvp_print(const u_char *, u_int);
@@ -336,7 +337,6 @@ extern void bpf_dump(struct bpf_program
 
 #endif
 
-#include "netdissect.h"
 
 /* forward compatibility */
 
Index: tcpdump-3.9.8/print-udp.c
===================================================================
--- tcpdump-3.9.8.orig/print-udp.c	2014-12-11 17:58:11.590537239 +0100
+++ tcpdump-3.9.8/print-udp.c	2014-12-11 17:59:02.893155872 +0100
@@ -416,7 +416,7 @@ udpipaddr_print(const struct ip *ip, int
 }
 
 void
-udp_print(register const u_char *bp, u_int length,
+udp_print(netdissect_options *ndo, register const u_char *bp, u_int length,
 	  register const u_char *bp2, int fragmented)
 {
 	register const struct udphdr *up;
@@ -675,7 +675,7 @@ udp_print(register const u_char *bp, u_i
                 else if (ISPORT(LDP_PORT))
 			ldp_print((const u_char *)(up + 1), length);
                 else if (ISPORT(OLSR_PORT))
-			olsr_print((const u_char *)(up + 1), length);
+			olsr_print(ndo, (const u_char *)(up + 1), length);
                 else if (ISPORT(MPLS_LSP_PING_PORT))
 			lspping_print((const u_char *)(up + 1), length);
 		else if (dport == BFD_CONTROL_PORT ||
