]> The Tcpdump Group git mirrors - tcpdump/blobdiff - print-rsvp.c
(for 4.9.3) CVE-2018-14880/OSPFv3: Fix a bounds check
[tcpdump] / print-rsvp.c
index 6e1acd673e99994d31c64f7c799d63a46ba0e9e0..438761ea36108caf0279b188e4688042cdd44db0 100644 (file)
  * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  * FOR A PARTICULAR PURPOSE.
  *
- * Original code by Hannes Gredler (hannes@juniper.net)
+ * Original code by Hannes Gredler (hannes@gredler.at)
  */
 
+/* \summary: Resource ReSerVation Protocol (RSVP) printer */
+
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #endif
@@ -30,7 +32,6 @@
 #include "signature.h"
 
 static const char tstr[] = " [|rsvp]";
-static const char istr[] = " (invalid)";
 
 /*
  * RFC 2205 common header
@@ -84,7 +85,7 @@ struct rsvp_object_header {
 #define        RSVP_MSGTYPE_PATHTEAR   5
 #define        RSVP_MSGTYPE_RESVTEAR   6
 #define        RSVP_MSGTYPE_RESVCONF   7
-#define RSVP_MSGTYPE_AGGREGATE  12
+#define RSVP_MSGTYPE_BUNDLE     12
 #define RSVP_MSGTYPE_ACK        13
 #define RSVP_MSGTYPE_HELLO_OLD  14      /* ancient Hellos */
 #define RSVP_MSGTYPE_SREFRESH   15
@@ -98,7 +99,7 @@ static const struct tok rsvp_msg_type_values[] = {
     { RSVP_MSGTYPE_PATHTEAR,   "PathTear" },
     { RSVP_MSGTYPE_RESVTEAR,   "ResvTear" },
     { RSVP_MSGTYPE_RESVCONF,   "ResvConf" },
-    { RSVP_MSGTYPE_AGGREGATE,  "Aggregate" },
+    { RSVP_MSGTYPE_BUNDLE,     "Bundle" },
     { RSVP_MSGTYPE_ACK,                "Acknowledgement" },
     { RSVP_MSGTYPE_HELLO_OLD,  "Hello (Old)" },
     { RSVP_MSGTYPE_SREFRESH,   "Refresh" },
@@ -498,6 +499,7 @@ rsvp_intserv_print(netdissect_options *ndo,
 
     if (obj_tlen < 4)
         return 0;
+    ND_TCHECK_8BITS(tptr);
     parameter_id = *(tptr);
     ND_TCHECK2(*(tptr + 2), 2);
     parameter_length = EXTRACT_16BITS(tptr+2)<<2; /* convert wordcount to bytecount */
@@ -520,9 +522,10 @@ rsvp_intserv_print(netdissect_options *ndo,
         * |        IS hop cnt (32-bit unsigned integer)                   |
         * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
         */
-        if (parameter_length == 4)
+        if (parameter_length == 4) {
            ND_TCHECK2(*(tptr + 4), 4);
             ND_PRINT((ndo, "\n\t\tIS hop count: %u", EXTRACT_32BITS(tptr + 4)));
+        }
         break;
 
     case 6:
@@ -567,9 +570,10 @@ rsvp_intserv_print(netdissect_options *ndo,
         * |      Composed MTU (32-bit unsigned integer)                   |
         * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
         */
-        if (parameter_length == 4)
+        if (parameter_length == 4) {
            ND_TCHECK2(*(tptr + 4), 4);
             ND_PRINT((ndo, "\n\t\tComposed MTU: %u bytes", EXTRACT_32BITS(tptr + 4)));
+        }
         break;
     case 127:
        /*
@@ -624,9 +628,10 @@ rsvp_intserv_print(netdissect_options *ndo,
     case 134:
     case 135:
     case 136:
-        if (parameter_length == 4)
+        if (parameter_length == 4) {
            ND_TCHECK2(*(tptr + 4), 4);
             ND_PRINT((ndo, "\n\t\tValue: %u", EXTRACT_32BITS(tptr + 4)));
+        }
         break;
 
     default:
@@ -1062,20 +1067,37 @@ rsvp_obj_print(netdissect_options *ndo,
             switch(rsvp_obj_ctype) {
             case RSVP_CTYPE_IPV4:
                 while(obj_tlen >= 4 ) {
+                   u_char length;
+
+                   ND_TCHECK2(*obj_tptr, 4);
+                   length = *(obj_tptr + 1);
                     ND_PRINT((ndo, "%s  Subobject Type: %s, length %u",
                            ident,
                            tok2str(rsvp_obj_xro_values,
                                    "Unknown %u",
                                    RSVP_OBJ_XRO_MASK_SUBOBJ(*obj_tptr)),
-                           *(obj_tptr + 1)));
+                           length));
 
-                    if (*(obj_tptr+1) == 0) { /* prevent infinite loops */
+                    if (length == 0) { /* prevent infinite loops */
                         ND_PRINT((ndo, "%s  ERROR: zero length ERO subtype", ident));
                         break;
                     }
 
                     switch(RSVP_OBJ_XRO_MASK_SUBOBJ(*obj_tptr)) {
+                   u_char prefix_length;
+
                     case RSVP_OBJ_XRO_IPV4:
+                       if (length != 8) {
+                               ND_PRINT((ndo, " ERROR: length != 8"));
+                               goto invalid;
+                       }
+                       ND_TCHECK2(*obj_tptr, 8);
+                       prefix_length = *(obj_tptr+6);
+                       if (prefix_length != 32) {
+                               ND_PRINT((ndo, " ERROR: Prefix length %u != 32",
+                                         prefix_length));
+                               goto invalid;
+                       }
                         ND_PRINT((ndo, ", %s, %s/%u, Flags: [%s]",
                                RSVP_OBJ_XRO_MASK_LOOSE(*obj_tptr) ? "Loose" : "Strict",
                                ipaddr_string(ndo, obj_tptr+2),
@@ -1085,6 +1107,11 @@ rsvp_obj_print(netdissect_options *ndo,
                                    *(obj_tptr + 7)))); /* rfc3209 says that this field is rsvd. */
                     break;
                     case RSVP_OBJ_XRO_LABEL:
+                       if (length != 8) {
+                               ND_PRINT((ndo, " ERROR: length != 8"));
+                               goto invalid;
+                       }
+                       ND_TCHECK2(*obj_tptr, 8);
                         ND_PRINT((ndo, ", Flags: [%s] (%#x), Class-Type: %s (%u), %u",
                                bittok2str(rsvp_obj_rro_label_flag_values,
                                    "none",
@@ -1179,6 +1206,17 @@ rsvp_obj_print(netdissect_options *ndo,
                /* read variable length subobjects */
                total_subobj_len = obj_tlen;
                 while(total_subobj_len > 0) {
+                    /* If RFC 3476 Section 3.1 defined that a sub-object of the
+                     * GENERALIZED_UNI RSVP object must have the Length field as
+                     * a multiple of 4, instead of the check below it would be
+                     * better to test total_subobj_len only once before the loop.
+                     * So long as it does not define it and this while loop does
+                     * not implement such a requirement, let's accept that within
+                     * each iteration subobj_len may happen to be a multiple of 1
+                     * and test it and total_subobj_len respectively.
+                     */
+                    if (total_subobj_len < 4)
+                        goto invalid;
                     subobj_len  = EXTRACT_16BITS(obj_tptr);
                     subobj_type = (EXTRACT_16BITS(obj_tptr+2))>>8;
                     af = (EXTRACT_16BITS(obj_tptr+2))&0x00FF;
@@ -1190,7 +1228,13 @@ rsvp_obj_print(netdissect_options *ndo,
                            tok2str(af_values, "Unknown", af), af,
                            subobj_len));
 
-                    if(subobj_len == 0)
+                    /* In addition to what is explained above, the same spec does not
+                     * explicitly say that the same Length field includes the 4-octet
+                     * sub-object header, but as long as this while loop implements it
+                     * as it does include, let's keep the check below consistent with
+                     * the rest of the code.
+                     */
+                    if(subobj_len < 4 || subobj_len > total_subobj_len)
                         goto invalid;
 
                     switch(subobj_type) {
@@ -1446,12 +1490,12 @@ rsvp_obj_print(netdissect_options *ndo,
         case RSVP_OBJ_FASTREROUTE:
             /* the differences between c-type 1 and 7 are minor */
             obj_ptr.rsvp_obj_frr = (const struct rsvp_obj_frr_t *)obj_tptr;
-            bw.i = EXTRACT_32BITS(obj_ptr.rsvp_obj_frr->bandwidth);
 
             switch(rsvp_obj_ctype) {
             case RSVP_CTYPE_1: /* new style */
                 if (obj_tlen < sizeof(struct rsvp_obj_frr_t))
                     return-1;
+                bw.i = EXTRACT_32BITS(obj_ptr.rsvp_obj_frr->bandwidth);
                 ND_PRINT((ndo, "%s  Setup Priority: %u, Holding Priority: %u, Hop-limit: %u, Bandwidth: %.10g Mbps",
                        ident,
                        (int)obj_ptr.rsvp_obj_frr->setup_prio,
@@ -1470,6 +1514,7 @@ rsvp_obj_print(netdissect_options *ndo,
             case RSVP_CTYPE_TUNNEL_IPV4: /* old style */
                 if (obj_tlen < 16)
                     return-1;
+                bw.i = EXTRACT_32BITS(obj_ptr.rsvp_obj_frr->bandwidth);
                 ND_PRINT((ndo, "%s  Setup Priority: %u, Holding Priority: %u, Hop-limit: %u, Bandwidth: %.10g Mbps",
                        ident,
                        (int)obj_ptr.rsvp_obj_frr->setup_prio,
@@ -1510,6 +1555,7 @@ rsvp_obj_print(netdissect_options *ndo,
         case RSVP_OBJ_CLASSTYPE_OLD: /* fall through */
             switch(rsvp_obj_ctype) {
             case RSVP_CTYPE_1:
+                ND_TCHECK_32BITS(obj_tptr);
                 ND_PRINT((ndo, "%s  CT: %u",
                        ident,
                        EXTRACT_32BITS(obj_tptr) & 0x7));
@@ -1804,8 +1850,8 @@ rsvp_print(netdissect_options *ndo,
            register const u_char *pptr, register u_int len)
 {
     const struct rsvp_common_header *rsvp_com_header;
-    const u_char *tptr,*subtptr;
-    u_short plen, tlen, subtlen;
+    const u_char *tptr;
+    u_short plen, tlen;
 
     tptr=pptr;
 
@@ -1854,10 +1900,19 @@ rsvp_print(netdissect_options *ndo,
 
     switch(rsvp_com_header->msg_type) {
 
-    case RSVP_MSGTYPE_AGGREGATE:
+    case RSVP_MSGTYPE_BUNDLE:
+        /*
+         * Process each submessage in the bundle message.
+         * Bundle messages may not contain bundle submessages, so we don't
+         * need to handle bundle submessages specially.
+         */
         while(tlen > 0) {
-            subtptr=tptr;
-            rsvp_com_header = (const struct rsvp_common_header *)subtptr;
+            const u_char *subpptr=tptr, *subtptr;
+            u_short subplen, subtlen;
+
+            subtptr=subpptr;
+
+            rsvp_com_header = (const struct rsvp_common_header *)subpptr;
             ND_TCHECK(*rsvp_com_header);
 
             /*
@@ -1868,7 +1923,8 @@ rsvp_print(netdissect_options *ndo,
                        RSVP_EXTRACT_VERSION(rsvp_com_header->version_flags)));
                 return;
             }
-            subtlen=EXTRACT_16BITS(rsvp_com_header->length);
+
+            subplen = subtlen = EXTRACT_16BITS(rsvp_com_header->length);
 
             ND_PRINT((ndo, "\n\t  RSVPv%u %s Message (%u), Flags: [%s], length: %u, ttl: %u, checksum: 0x%04x",
                    RSVP_EXTRACT_VERSION(rsvp_com_header->version_flags),
@@ -1894,7 +1950,10 @@ rsvp_print(netdissect_options *ndo,
             subtptr+=sizeof(const struct rsvp_common_header);
             subtlen-=sizeof(const struct rsvp_common_header);
 
-            if (rsvp_obj_print(ndo, pptr, plen, subtptr, "\n\t    ", subtlen, rsvp_com_header) == -1)
+            /*
+             * Print all objects in the submessage.
+             */
+            if (rsvp_obj_print(ndo, subpptr, subplen, subtptr, "\n\t    ", subtlen, rsvp_com_header) == -1)
                 return;
 
             tptr+=subtlen+sizeof(const struct rsvp_common_header);
@@ -1914,6 +1973,9 @@ rsvp_print(netdissect_options *ndo,
     case RSVP_MSGTYPE_HELLO:
     case RSVP_MSGTYPE_ACK:
     case RSVP_MSGTYPE_SREFRESH:
+        /*
+         * Print all objects in the message.
+         */
         if (rsvp_obj_print(ndo, pptr, plen, tptr, "\n\t  ", tlen, rsvp_com_header) == -1)
             return;
         break;