BER: Add a length check.
authorGerald Combs <gerald@wireshark.org>
Tue, 20 Feb 2018 19:29:49 +0000 (11:29 -0800)
committerMichael Mann <mmann78@netscape.net>
Wed, 21 Feb 2018 01:06:51 +0000 (01:06 +0000)
Add a common large length reporting function. Add a length check to
dissect_ber_set.

Bug: 14444.
Change-Id: I6093b5342439cd0ee08f060b8d74b3ae54b3b8f8
Reviewed-on: https://code.wireshark.org/review/25931
Reviewed-by: Gerald Combs <gerald@wireshark.org>
Petri-Dish: Gerald Combs <gerald@wireshark.org>
Tested-by: Petri Dish Buildbot
Reviewed-by: Michael Mann <mmann78@netscape.net>
epan/dissectors/packet-ber.c

index 17a1440af5e288c8d6a1e78e6ec4e8e7150efff4..43d54fc0981e4e15421d36feb45b988df2b0e8a5 100644 (file)
@@ -704,6 +704,23 @@ ber_add_bad_length_error(packet_info *pinfo, proto_tree *tree,
     return ti;
 }
 
+/*
+ * Add an "exceeds tvb length" error.
+ */
+static void
+ber_add_large_length_error(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb,
+                         const gint offset, const guint32 length)
+{
+    proto_item *cause;
+
+    cause = proto_tree_add_string_format_value(
+        tree, hf_ber_error, tvb, offset, length, "illegal_length",
+        "length %u longer than tvb_reported_length_remaining: %d",
+        length,
+        tvb_reported_length_remaining(tvb, offset));
+    expert_add_info(pinfo, cause, &ei_ber_error_length);
+}
+
 /*
  * Like proto_tree_add_item(), but checks whether the length of the item
  * being added is appropriate for the type of the item being added, so
@@ -842,12 +859,7 @@ try_dissect_unknown_ber(packet_info *pinfo, tvbuff_t *tvb, volatile int offset,
             offset = dissect_ber_identifier(pinfo, tree, tvb, start_offset, &ber_class, &pc, &tag);
             offset = dissect_ber_length(pinfo, tree, tvb, offset, &len, NULL);
         }
-        cause = proto_tree_add_string_format_value(
-            tree, hf_ber_error, tvb, offset, len, "illegal_length",
-            "length:%u longer than tvb_reported_length_remaining:%d",
-            len,
-            tvb_reported_length_remaining(tvb, offset));
-        expert_add_info(pinfo, cause, &ei_ber_error_length);
+        ber_add_large_length_error(pinfo, tree, tvb, offset, len);
         return tvb_reported_length(tvb);
     }
 /* we don't care about the class only on the constructor flag */
@@ -1589,12 +1601,7 @@ proto_tree_add_debug_text(tree, "OCTET STRING dissect_ber_octet_string(%s) enter
              * error - short frame, or this item runs past the
              * end of the item containing it
              */
-            cause = proto_tree_add_string_format_value(
-                tree, hf_ber_error, tvb, offset, len, "illegal_length",
-                "length:%u longer than tvb_reported_length_remaining:%d",
-                len,
-                len_remain);
-            expert_add_info(actx->pinfo, cause, &ei_ber_error_length);
+            ber_add_large_length_error(actx->pinfo, tree, tvb, offset, len);
             return end_offset;
         }
 
@@ -2053,12 +2060,7 @@ dissect_ber_real(gboolean implicit_tag, asn1_ctx_t *actx, proto_tree *tree, tvbu
         len_remain = (guint32)tvb_reported_length_remaining(tvb, offset);
         if (len_remain < val_length) {
             /* error - this item runs past the end of the item containing it */
-            cause = proto_tree_add_string_format_value(
-                tree, hf_ber_error, tvb, offset, val_length, "illegal_length",
-                "length:%u longer than tvb_reported_length_remaining:%d",
-                val_length,
-                len_remain);
-            expert_add_info(actx->pinfo, cause, &ei_ber_error_length);
+            ber_add_large_length_error(actx->pinfo, tree, tvb, offset, val_length);
             return end_offset;
         }
     }
@@ -2560,13 +2562,17 @@ proto_tree_add_debug_text(tree, "SET dissect_ber_set(%s) entered\n", name);
         offset  = get_ber_length(tvb, offset, &len, &ind_field);
         eoffset = offset + len;
 
+        if (len > (guint32)(end_offset - offset) || len > (guint32) tvb_reported_length_remaining(tvb, offset)) {
+            ber_add_large_length_error(actx->pinfo, tree, tvb, offset, len);
+            return end_offset;
+        }
+
         /* Look through the Set to see if this class/id exists and
          * hasn't been seen before
          * Skip check completely if ber_class == ANY
          * of if NOCHKTAG is set
          */
 
-
         for (first_pass = TRUE, cset = set, set_idx = 0; cset->func || first_pass; cset++, set_idx++) {
 
             /* we reset for a second pass when we will look for choices */