]> The Tcpdump Group git mirrors - tcpdump/blobdiff - print-mobility.c
test case for cve2015-0261 -- corrupted IPv6 mobility header
[tcpdump] / print-mobility.c
index 9dfb6eb2fa5b2113827a01ff0e345a16a5708e53..b6fa61e9dc747463a10cd1c5a7f75f84f171320f 100644 (file)
 
 /* Mobility header */
 struct ip6_mobility {
-       u_int8_t ip6m_pproto;   /* following payload protocol (for PG) */
-       u_int8_t ip6m_len;      /* length in units of 8 octets */
-       u_int8_t ip6m_type;     /* message type */
-       u_int8_t reserved;      /* reserved */
-       u_int16_t ip6m_cksum;   /* sum of IPv6 pseudo-header and MH */
+       uint8_t ip6m_pproto;    /* following payload protocol (for PG) */
+       uint8_t ip6m_len;       /* length in units of 8 octets */
+       uint8_t ip6m_type;      /* message type */
+       uint8_t reserved;       /* reserved */
+       uint16_t ip6m_cksum;    /* sum of IPv6 pseudo-header and MH */
        union {
-               u_int16_t       ip6m_un_data16[1]; /* type-specific field */
-               u_int8_t        ip6m_un_data8[2];  /* type-specific fiedl */
+               uint16_t        ip6m_un_data16[1]; /* type-specific field */
+               uint8_t         ip6m_un_data8[2];  /* type-specific field */
        } ip6m_dataun;
 };
 
@@ -69,6 +69,18 @@ struct ip6_mobility {
 #define IP6M_BINDING_UPDATE    5       /* Binding Update */
 #define IP6M_BINDING_ACK       6       /* Binding Acknowledgement */
 #define IP6M_BINDING_ERROR     7       /* Binding Error */
+#define IP6M_MAX               7
+
+static const unsigned ip6m_hdrlen[IP6M_MAX + 1] = {
+       IP6M_MINLEN,      /* IP6M_BINDING_REQUEST  */
+       IP6M_MINLEN + 8,  /* IP6M_HOME_TEST_INIT   */
+       IP6M_MINLEN + 8,  /* IP6M_CAREOF_TEST_INIT */
+       IP6M_MINLEN + 16, /* IP6M_HOME_TEST        */
+       IP6M_MINLEN + 16, /* IP6M_CAREOF_TEST      */
+       IP6M_MINLEN + 4,  /* IP6M_BINDING_UPDATE   */
+       IP6M_MINLEN + 4,  /* IP6M_BINDING_ACK      */
+       IP6M_MINLEN + 16, /* IP6M_BINDING_ERROR    */
+};
 
 /* XXX: unused */
 #define IP6MOPT_BU_MINLEN      10
@@ -95,16 +107,20 @@ mobility_opt_print(netdissect_options *ndo,
        unsigned i, optlen;
 
        for (i = 0; i < len; i += optlen) {
+               ND_TCHECK(bp[i]);
                if (bp[i] == IP6MOPT_PAD1)
                        optlen = 1;
                else {
-                       if (i + 1 < len)
+                       if (i + 1 < len) {
+                               ND_TCHECK(bp[i + 1]);
                                optlen = bp[i + 1] + 2;
+                       }
                        else
                                goto trunc;
                }
                if (i + optlen > len)
                        goto trunc;
+               ND_TCHECK(bp[i + optlen]);
 
                switch (bp[i]) {
                case IP6MOPT_PAD1:
@@ -174,7 +190,7 @@ mobility_print(netdissect_options *ndo,
        const struct ip6_mobility *mh;
        const u_char *ep;
        unsigned mhlen, hlen;
-       u_int8_t type;
+       uint8_t type;
 
        mh = (struct ip6_mobility *)bp;
 
@@ -203,6 +219,10 @@ mobility_print(netdissect_options *ndo,
 
        ND_TCHECK(mh->ip6m_type);
        type = mh->ip6m_type;
+       if (type <= IP6M_MAX && mhlen < ip6m_hdrlen[type]) {
+               ND_PRINT((ndo, "(header length %u is too small for type %u)", mhlen, type));
+               goto trunc;
+       }
        switch (type) {
        case IP6M_BINDING_REQUEST:
                ND_PRINT((ndo, "mobility: BRR"));