9c49d5a
From 3b223228a87434f214ea3f80d9af420491a76434 Mon Sep 17 00:00:00 2001
9c49d5a
From: Guy Harris <guy@alum.mit.edu>
9c49d5a
Date: Tue, 11 Nov 2014 16:49:39 -0800
9c49d5a
Subject: [PATCH 9/9] Do more bounds checking and length checking.
9c49d5a
9c49d5a
Don't run past the end of the captured data, and don't run past the end
9c49d5a
of the packet (i.e., don't make the length variable go negative).
9c49d5a
9c49d5a
Also, stop dissecting if the message length isn't valid.
9c49d5a
---
9c49d5a
 print-olsr.c | 56 +++++++++++++++++++++++++++++++++++++++++++-------------
9c49d5a
 1 file changed, 43 insertions(+), 13 deletions(-)
9c49d5a
9c49d5a
diff --git a/print-olsr.c b/print-olsr.c
9c49d5a
index 6fa0d76..6d2d65f 100644
9c49d5a
--- a/print-olsr.c
9c49d5a
+++ b/print-olsr.c
9c49d5a
@@ -178,7 +178,7 @@ struct olsr_lq_neighbor6 {
9c49d5a
 /*
9c49d5a
  * print a neighbor list with LQ extensions.
9c49d5a
  */
9c49d5a
-static void
9c49d5a
+static int
9c49d5a
 olsr_print_lq_neighbor4(netdissect_options *ndo,
9c49d5a
                         const u_char *msg_data, u_int hello_len)
9c49d5a
 {
9c49d5a
@@ -187,6 +187,8 @@ olsr_print_lq_neighbor4(netdissect_options *ndo,
9c49d5a
     while (hello_len >= sizeof(struct olsr_lq_neighbor4)) {
9c49d5a
 
9c49d5a
         lq_neighbor = (struct olsr_lq_neighbor4 *)msg_data;
9c49d5a
+        if (!ND_TTEST(*lq_neighbor))
9c49d5a
+            return (-1);
9c49d5a
 
9c49d5a
         ND_PRINT((ndo, "\n\t      neighbor %s, link-quality %.2lf%%"
9c49d5a
                ", neighbor-link-quality %.2lf%%",
9c49d5a
@@ -197,10 +199,11 @@ olsr_print_lq_neighbor4(netdissect_options *ndo,
9c49d5a
         msg_data += sizeof(struct olsr_lq_neighbor4);
9c49d5a
         hello_len -= sizeof(struct olsr_lq_neighbor4);
9c49d5a
     }
9c49d5a
+    return (0);
9c49d5a
 }
9c49d5a
 
9c49d5a
 #if INET6
9c49d5a
-static void
9c49d5a
+static int
9c49d5a
 olsr_print_lq_neighbor6(netdissect_options *ndo,
9c49d5a
                         const u_char *msg_data, u_int hello_len)
9c49d5a
 {
9c49d5a
@@ -209,6 +212,8 @@ olsr_print_lq_neighbor6(netdissect_options *ndo,
9c49d5a
     while (hello_len >= sizeof(struct olsr_lq_neighbor6)) {
9c49d5a
 
9c49d5a
         lq_neighbor = (struct olsr_lq_neighbor6 *)msg_data;
9c49d5a
+        if (!ND_TTEST(*lq_neighbor))
9c49d5a
+            return (-1);
9c49d5a
 
9c49d5a
         ND_PRINT((ndo, "\n\t      neighbor %s, link-quality %.2lf%%"
9c49d5a
                ", neighbor-link-quality %.2lf%%",
9c49d5a
@@ -219,13 +224,14 @@ olsr_print_lq_neighbor6(netdissect_options *ndo,
9c49d5a
         msg_data += sizeof(struct olsr_lq_neighbor6);
9c49d5a
         hello_len -= sizeof(struct olsr_lq_neighbor6);
9c49d5a
     }
9c49d5a
+    return (0);
9c49d5a
 }
9c49d5a
 #endif /* INET6 */
9c49d5a
 
9c49d5a
 /*
9c49d5a
  * print a neighbor list.
9c49d5a
  */
9c49d5a
-static void
9c49d5a
+static int
9c49d5a
 olsr_print_neighbor(netdissect_options *ndo,
9c49d5a
                     const u_char *msg_data, u_int hello_len)
9c49d5a
 {
9c49d5a
@@ -236,6 +242,8 @@ olsr_print_neighbor(netdissect_options *ndo,
9c49d5a
 
9c49d5a
     while (hello_len >= sizeof(struct in_addr)) {
9c49d5a
 
9c49d5a
+        if (!ND_TTEST2(*msg_data, sizeof(struct in_addr)))
9c49d5a
+            return (-1);
9c49d5a
         /* print 4 neighbors per line */
9c49d5a
 
9c49d5a
         ND_PRINT((ndo, "%s%s", ipaddr_string(ndo, msg_data),
9c49d5a
@@ -244,6 +252,7 @@ olsr_print_neighbor(netdissect_options *ndo,
9c49d5a
         msg_data += sizeof(struct in_addr);
9c49d5a
         hello_len -= sizeof(struct in_addr);
9c49d5a
     }
9c49d5a
+    return (0);
9c49d5a
 }
9c49d5a
 
9c49d5a
 
9c49d5a
@@ -326,6 +335,9 @@ olsr_print(netdissect_options *ndo,
9c49d5a
                     ME_TO_DOUBLE(msgptr.v6->vtime),
9c49d5a
                     EXTRACT_16BITS(msgptr.v6->msg_seq),
9c49d5a
                     msg_len, (msg_len_valid == 0) ? " (invalid)" : ""));
9c49d5a
+            if (!msg_len_valid) {
9c49d5a
+                return;
9c49d5a
+            }
9c49d5a
 
9c49d5a
             msg_tlen = msg_len - sizeof(struct olsr_msg6);
9c49d5a
             msg_data = tptr + sizeof(struct olsr_msg6);
9c49d5a
@@ -354,6 +366,9 @@ olsr_print(netdissect_options *ndo,
9c49d5a
                     ME_TO_DOUBLE(msgptr.v4->vtime),
9c49d5a
                     EXTRACT_16BITS(msgptr.v4->msg_seq),
9c49d5a
                     msg_len, (msg_len_valid == 0) ? " (invalid)" : ""));
9c49d5a
+            if (!msg_len_valid) {
9c49d5a
+                return;
9c49d5a
+            }
9c49d5a
 
9c49d5a
             msg_tlen = msg_len - sizeof(struct olsr_msg4);
9c49d5a
             msg_data = tptr + sizeof(struct olsr_msg4);
9c49d5a
@@ -362,6 +377,8 @@ olsr_print(netdissect_options *ndo,
9c49d5a
         switch (msg_type) {
9c49d5a
         case OLSR_HELLO_MSG:
9c49d5a
         case OLSR_HELLO_LQ_MSG:
9c49d5a
+            if (msg_tlen < sizeof(struct olsr_hello))
9c49d5a
+                goto trunc;
9c49d5a
             ND_TCHECK2(*msg_data, sizeof(struct olsr_hello));
9c49d5a
 
9c49d5a
             ptr.hello = (struct olsr_hello *)msg_data;
9c49d5a
@@ -401,15 +418,21 @@ olsr_print(netdissect_options *ndo,
9c49d5a
                 msg_tlen -= sizeof(struct olsr_hello_link);
9c49d5a
                 hello_len -= sizeof(struct olsr_hello_link);
9c49d5a
 
9c49d5a
+                ND_TCHECK2(*msg_data, hello_len);
9c49d5a
                 if (msg_type == OLSR_HELLO_MSG) {
9c49d5a
-                    olsr_print_neighbor(ndo, msg_data, hello_len);
9c49d5a
+                    if (olsr_print_neighbor(ndo, msg_data, hello_len) == -1)
9c49d5a
+                        goto trunc;
9c49d5a
                 } else {
9c49d5a
 #if INET6
9c49d5a
-                    if (is_ipv6)
9c49d5a
-                        olsr_print_lq_neighbor6(ndo, msg_data, hello_len);
9c49d5a
-                    else
9c49d5a
+                    if (is_ipv6) {
9c49d5a
+                        if (olsr_print_lq_neighbor6(ndo, msg_data, hello_len) == -1)
9c49d5a
+                            goto trunc;
9c49d5a
+                    } else
9c49d5a
 #endif
9c49d5a
-                        olsr_print_lq_neighbor4(ndo, msg_data, hello_len);
9c49d5a
+                    {
9c49d5a
+                        if (olsr_print_lq_neighbor4(ndo, msg_data, hello_len) == -1)
9c49d5a
+                            goto trunc;
9c49d5a
+                    }
9c49d5a
                 }
9c49d5a
 
9c49d5a
                 msg_data += hello_len;
9c49d5a
@@ -419,6 +442,8 @@ olsr_print(netdissect_options *ndo,
9c49d5a
 
9c49d5a
         case OLSR_TC_MSG:
9c49d5a
         case OLSR_TC_LQ_MSG:
9c49d5a
+            if (msg_tlen < sizeof(struct olsr_tc))
9c49d5a
+                goto trunc;
9c49d5a
             ND_TCHECK2(*msg_data, sizeof(struct olsr_tc));
9c49d5a
 
9c49d5a
             ptr.tc = (struct olsr_tc *)msg_data;
9c49d5a
@@ -428,14 +453,19 @@ olsr_print(netdissect_options *ndo,
9c49d5a
             msg_tlen -= sizeof(struct olsr_tc);
9c49d5a
 
9c49d5a
             if (msg_type == OLSR_TC_MSG) {
9c49d5a
-                olsr_print_neighbor(ndo, msg_data, msg_tlen);
9c49d5a
+                if (olsr_print_neighbor(ndo, msg_data, msg_tlen) == -1)
9c49d5a
+                    goto trunc;
9c49d5a
             } else {
9c49d5a
 #if INET6
9c49d5a
-                if (is_ipv6)
9c49d5a
-                    olsr_print_lq_neighbor6(ndo, msg_data, msg_tlen);
9c49d5a
-                else
9c49d5a
+                if (is_ipv6) {
9c49d5a
+                    if (olsr_print_lq_neighbor6(ndo, msg_data, msg_tlen) == -1)
9c49d5a
+                        goto trunc;
9c49d5a
+                } else
9c49d5a
 #endif
9c49d5a
-                    olsr_print_lq_neighbor4(ndo, msg_data, msg_tlen);
9c49d5a
+                {
9c49d5a
+                    if (olsr_print_lq_neighbor4(ndo, msg_data, msg_tlen) == -1)
9c49d5a
+                        goto trunc;
9c49d5a
+                }
9c49d5a
             }
9c49d5a
             break;
9c49d5a
 
9c49d5a
-- 
9c49d5a
1.8.3.1
9c49d5a