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-4.5.1/print-olsr.c
===================================================================
--- tcpdump-4.5.1.orig/print-olsr.c	2013-11-08 00:22:54.000000000 +0100
+++ tcpdump-4.5.1/print-olsr.c	2014-12-11 17:39:48.294191835 +0100
@@ -181,14 +181,16 @@ struct olsr_lq_neighbor6 {
 /*
  * print a neighbor list with LQ extensions.
  */
-static void
-olsr_print_lq_neighbor4 (const u_char *msg_data, u_int hello_len)
+static int
+olsr_print_lq_neighbor4 (netdissect_options *ndo, const u_char *msg_data, u_int hello_len)
 {
     struct olsr_lq_neighbor4 *lq_neighbor;
 
     while (hello_len >= sizeof(struct olsr_lq_neighbor4)) {
 
         lq_neighbor = (struct olsr_lq_neighbor4 *)msg_data;
+        if (!ND_TTEST(*lq_neighbor))
+            return (-1);
 
         printf("\n\t      neighbor %s, link-quality %.2lf%%"
                ", neighbor-link-quality %.2lf%%",
@@ -199,17 +201,20 @@ olsr_print_lq_neighbor4 (const u_char *m
         msg_data += sizeof(struct olsr_lq_neighbor4);
         hello_len -= sizeof(struct olsr_lq_neighbor4);
     }
+    return (0);
 }
 
 #if INET6
-static void
-olsr_print_lq_neighbor6 (const u_char *msg_data, u_int hello_len)
+static int
+olsr_print_lq_neighbor6 (netdissect_options *ndo, const u_char *msg_data, u_int hello_len)
 {
     struct olsr_lq_neighbor6 *lq_neighbor;
 
     while (hello_len >= sizeof(struct olsr_lq_neighbor6)) {
 
         lq_neighbor = (struct olsr_lq_neighbor6 *)msg_data;
+        if (!ND_TTEST(*lq_neighbor))
+            return (-1);
 
         printf("\n\t      neighbor %s, link-quality %.2lf%%"
                ", neighbor-link-quality %.2lf%%",
@@ -220,14 +225,15 @@ olsr_print_lq_neighbor6 (const u_char *m
         msg_data += sizeof(struct olsr_lq_neighbor6);
         hello_len -= sizeof(struct olsr_lq_neighbor6);
     }
+    return (0);
 }
 #endif /* INET6 */
 
 /*
  * 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;
 
@@ -236,6 +242,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),
@@ -244,11 +252,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, int is_ipv6)
+olsr_print (netdissect_options *ndo, const u_char *pptr, u_int length, int is_ipv6)
 {
     union {
         const struct olsr_common *common;
@@ -328,6 +337,9 @@ olsr_print (const u_char *pptr, u_int le
                     ME_TO_DOUBLE(msgptr.v6->vtime),
                     EXTRACT_16BITS(msgptr.v6->msg_seq),
                     msg_len, (msg_len_valid == 0) ? " (invalid)" : "");
+            if (!msg_len_valid) {
+                return;
+		}
 
             msg_tlen = msg_len - sizeof(struct olsr_msg6);
             msg_data = tptr + sizeof(struct olsr_msg6);
@@ -356,6 +368,9 @@ olsr_print (const u_char *pptr, u_int le
                     ME_TO_DOUBLE(msgptr.v4->vtime),
                     EXTRACT_16BITS(msgptr.v4->msg_seq),
                     msg_len, (msg_len_valid == 0) ? " (invalid)" : "");
+            if (!msg_len_valid) {
+                return;
+            }
 
             msg_tlen = msg_len - sizeof(struct olsr_msg4);
             msg_data = tptr + sizeof(struct olsr_msg4);
@@ -364,6 +379,8 @@ olsr_print (const u_char *pptr, u_int le
         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;
 
@@ -405,15 +422,20 @@ 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);
+                    if (olsr_print_neighbor(ndo, msg_data, hello_len) == -1)
+			goto trunc;
                 } else {
 #if INET6
                     if (is_ipv6)
-                        olsr_print_lq_neighbor6(msg_data, hello_len);
+                        if (olsr_print_lq_neighbor6(ndo, msg_data, hello_len) == -1)
+				goto trunc;
                     else
 #endif
-                        olsr_print_lq_neighbor4(msg_data, hello_len);
+                        if (olsr_print_lq_neighbor4(ndo, msg_data, hello_len) == -1)
+                            goto trunc;
                 }
 
                 msg_data += hello_len;
@@ -423,6 +445,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;
 
@@ -433,14 +457,17 @@ 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);
+                if (olsr_print_neighbor(ndo, msg_data, msg_tlen) == -1)
+                    goto trunc;
             } else {
 #if INET6
                 if (is_ipv6)
-                    olsr_print_lq_neighbor6(msg_data, msg_tlen);
+                    if (olsr_print_lq_neighbor6(ndo, msg_data, msg_tlen) == -1)
+                        goto trunc;
                 else
 #endif
-                    olsr_print_lq_neighbor4(msg_data, msg_tlen);
+                    if (olsr_print_lq_neighbor4(ndo, msg_data, msg_tlen) == -1)
+                        goto trunc;
             }
             break;
 
Index: tcpdump-4.5.1/interface.h
===================================================================
--- tcpdump-4.5.1.orig/interface.h	2013-11-08 00:22:54.000000000 +0100
+++ tcpdump-4.5.1/interface.h	2014-12-11 17:38:25.622187779 +0100
@@ -174,6 +174,7 @@ extern u_int16_t create_osi_cksum(const
 /* 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);
@@ -242,7 +243,7 @@ extern void ntp_print(const u_char *, u_
 extern u_int null_if_print(const struct pcap_pkthdr *, const u_char *);
 extern void openflow_print(const u_char *, u_int);
 extern void ospf_print(const u_char *, u_int, const u_char *);
-extern void olsr_print (const u_char *, u_int, int);
+extern void olsr_print (netdissect_options *, const u_char *, u_int, 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);
@@ -375,7 +376,6 @@ extern void bpf_dump(const struct bpf_pr
 
 #endif
 
-#include "netdissect.h"
 
 /* forward compatibility */
 
Index: tcpdump-4.5.1/print-udp.c
===================================================================
--- tcpdump-4.5.1.orig/print-udp.c	2014-12-11 17:37:53.398796456 +0100
+++ tcpdump-4.5.1/print-udp.c	2014-12-11 17:41:50.374672485 +0100
@@ -356,7 +356,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;
@@ -651,7 +651,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,
 #if INET6
 					(IP_V(ip) == 6) ? 1 : 0);
 #else
