]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
ipv6: make exthdr parsing more robust
authorVictor Julien <victor@inliniac.net>
Thu, 24 Jul 2014 14:50:34 +0000 (16:50 +0200)
committerVictor Julien <victor@inliniac.net>
Wed, 6 Aug 2014 08:56:05 +0000 (10:56 +0200)
Improve data length checks. Detect PadN option with 0 length.

rules/decoder-events.rules
src/decode-events.h
src/decode-ipv6.c
src/detect-engine-event.h

index 9a3fb674eb19a4320741e0cdac88227ac7a83c48..e711c21e735757b6ef50f6e30ad06213b08e6d3a 100644 (file)
@@ -37,6 +37,8 @@ alert pkthdr any any -> any any (msg:"SURICATA IPv6 DSTOPTS unknown option"; dec
 alert pkthdr any any -> any any (msg:"SURICATA IPv6 DSTOPTS only padding"; decode-event:ipv6.dstopts_only_padding; sid:2200089; rev:1;)
 # Type 0 Routing header deprecated per RFC 5095
 alert ipv6 any any -> any any (msg:"SURICATA RH Type 0"; decode-event:ipv6.rh_type_0; sid:2200093; rev:1;)
+# padN option with zero length field
+alert ipv6 any any -> any any (msg:"SURICATA zero length padN option"; decode-event:ipv6.zero_len_padn; sid:2200094; rev:1;)
 alert ipv6 any any -> any any (msg:"SURICATA IPv6 with ICMPv4 header"; decode-event:ipv6.icmpv4; sid:2200090; rev:1;)
 alert pkthdr any any -> any any (msg:"SURICATA ICMPv4 packet too small"; decode-event:icmpv4.pkt_too_small; sid:2200023; rev:1;)
 alert pkthdr any any -> any any (msg:"SURICATA ICMPv4 unknown type"; decode-event:icmpv4.unknown_type; sid:2200024; rev:1;)
@@ -108,5 +110,5 @@ alert pkthdr any any -> any any (msg:"SURICATA IPv4-in-IPv6 invalid protocol"; d
 alert pkthdr any any -> any any (msg:"SURICATA IPv6-in-IPv6 packet too short"; decode-event:ipv6.ipv6_in_ipv6_too_small; sid:2200084; rev:1;)
 alert pkthdr any any -> any any (msg:"SURICATA IPv6-in-IPv6 invalid protocol"; decode-event:ipv6.ipv6_in_ipv6_wrong_version; sid:2200085; rev:1;)
 
-# next sid is 2200094
+# next sid is 2200095
 
index bedb821db6bff0ac9389e17c5381be17fb3bd0b3..998da633e9738330f772da827cc61ad0c53f6716 100644 (file)
@@ -80,6 +80,7 @@ enum {
     IPV6_DSTOPTS_ONLY_PADDING,      /**< all options in DST opts are padding */
 
     IPV6_EXTHDR_RH_TYPE_0,          /**< RH 0 is deprecated as per rfc5095 */
+    IPV6_EXTHDR_ZERO_LEN_PADN,      /**< padN w/o data (0 len) */
 
     IPV6_WITH_ICMPV4,               /**< IPv6 packet with ICMPv4 header */
 
index 84c1b54d4f7dcf2e5e90d6851b7b468a9aab3e1b..95f3b9dd3e131c6f4b2d9a48125c4e9841d20c83 100644 (file)
@@ -298,15 +298,39 @@ DecodeIPV6ExtHdrs(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt
                         continue;
                     }
 
+                    if (offset + 1 >= optslen) {
+                        ENGINE_SET_EVENT(p, IPV6_EXTHDR_INVALID_OPTLEN);
+                        break;
+                    }
+
+                    /* length field for each opt */
+                    uint8_t ip6_optlen = *(ptr + 1);
+
+                    /* see if the optlen from the packet fits the total optslen */
+                    if ((offset + 1 + ip6_optlen) > optslen) {
+                        ENGINE_SET_EVENT(p, IPV6_EXTHDR_INVALID_OPTLEN);
+                        break;
+                    }
+
                     if (*ptr == IPV6OPT_PADN) /* PadN */
                     {
                         //printf("PadN option\n");
                         padn_cnt++;
+
+                        /* a zero padN len would be weird */
+                        if (ip6_optlen == 0)
+                            ENGINE_SET_EVENT(p, IPV6_EXTHDR_ZERO_LEN_PADN);
                     }
                     else if (*ptr == IPV6OPT_RA) /* RA */
                     {
                         ra->ip6ra_type = *(ptr);
-                        ra->ip6ra_len  = *(ptr + 1);
+                        ra->ip6ra_len  = ip6_optlen;
+
+                        if (ip6_optlen < sizeof(ra->ip6ra_value)) {
+                            ENGINE_SET_EVENT(p, IPV6_EXTHDR_INVALID_OPTLEN);
+                            break;
+                        }
+
                         memcpy(&ra->ip6ra_value, (ptr + 2), sizeof(ra->ip6ra_value));
                         ra->ip6ra_value = ntohs(ra->ip6ra_value);
                         //printf("RA option: type %" PRIu32 " len %" PRIu32 " value %" PRIu32 "\n",
@@ -316,7 +340,13 @@ DecodeIPV6ExtHdrs(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt
                     else if (*ptr == IPV6OPT_JUMBO) /* Jumbo */
                     {
                         jumbo->ip6j_type = *(ptr);
-                        jumbo->ip6j_len  = *(ptr+1);
+                        jumbo->ip6j_len  = ip6_optlen;
+
+                        if (ip6_optlen < sizeof(jumbo->ip6j_payload_len)) {
+                            ENGINE_SET_EVENT(p, IPV6_EXTHDR_INVALID_OPTLEN);
+                            break;
+                        }
+
                         memcpy(&jumbo->ip6j_payload_len, (ptr+2), sizeof(jumbo->ip6j_payload_len));
                         jumbo->ip6j_payload_len = ntohl(jumbo->ip6j_payload_len);
                         //printf("Jumbo option: type %" PRIu32 " len %" PRIu32 " payload len %" PRIu32 "\n",
@@ -325,7 +355,13 @@ DecodeIPV6ExtHdrs(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt
                     else if (*ptr == IPV6OPT_HAO) /* HAO */
                     {
                         hao->ip6hao_type = *(ptr);
-                        hao->ip6hao_len  = *(ptr+1);
+                        hao->ip6hao_len  = ip6_optlen;
+
+                        if (ip6_optlen < sizeof(hao->ip6hao_hoa)) {
+                            ENGINE_SET_EVENT(p, IPV6_EXTHDR_INVALID_OPTLEN);
+                            break;
+                        }
+
                         memcpy(&hao->ip6hao_hoa, (ptr+2), sizeof(hao->ip6hao_hoa));
                         //printf("HAO option: type %" PRIu32 " len %" PRIu32 " ",
                         //    hao->ip6hao_type, hao->ip6hao_len);
index ca4d1d05ec113157a9cbd73021581632b3556952..f4b3298c62d718106c88ed7cfea02cb4c8c30b93 100644 (file)
@@ -90,6 +90,7 @@ struct DetectEngineEvents_ {
     { "ipv6.dstopts_unknown_opt", IPV6_DSTOPTS_UNKNOWN_OPT, },
     { "ipv6.dstopts_only_padding", IPV6_DSTOPTS_ONLY_PADDING, },
     { "ipv6.rh_type_0", IPV6_EXTHDR_RH_TYPE_0, },
+    { "ipv6.zero_len_padn", IPV6_EXTHDR_ZERO_LEN_PADN, },
     { "ipv6.icmpv4", IPV6_WITH_ICMPV4, },
 
     /* TCP EVENTS */