]> git.itanic.dy.fi Git - linux-stable/commitdiff
[NETFILTER]: Fix ip6_tables protocol bypass bug (CVE-2006-4572)
authorPatrick McHardy <kaber@trash.net>
Sun, 5 Nov 2006 08:03:48 +0000 (09:03 +0100)
committerAdrian Bunk <bunk@stusta.de>
Sun, 5 Nov 2006 08:03:48 +0000 (09:03 +0100)
As reported by Mark Dowd <Mark_Dowd@McAfee.com>, ip6_tables is susceptible
to a fragmentation attack causing false negatives on protocol matches.

When the protocol header doesn't follow the fragment header immediately,
the fragment header contains the protocol number of the next extension
header. When the extension header and the protocol header are sent in
a second fragment a rule like "ip6tables .. -p udp -j DROP" will never
match.

Drop fragments that are at offset 0 and don't contain the final protocol
header regardless of the ruleset, since this should not happen normally.

With help from Yasuyuki KOZAKAI <yasuyuki.kozakai@toshiba.co.jp>.

Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: Adrian Bunk <bunk@stusta.de>
net/ipv6/netfilter/ip6_tables.c

index dd6ad4228aa6301f980392d0662b7b88fba0529e..a3e3da11b1c1a0d11420bdcf785997e24d823b92 100644 (file)
@@ -127,7 +127,7 @@ ip6_packet_match(const struct sk_buff *skb,
                 const char *outdev,
                 const struct ip6t_ip6 *ip6info,
                 unsigned int *protoff,
-                int *fragoff)
+                int *fragoff, int *hotdrop)
 {
        size_t i;
        unsigned long ret;
@@ -185,9 +185,11 @@ ip6_packet_match(const struct sk_buff *skb,
                unsigned short _frag_off;
 
                protohdr = ipv6_find_hdr(skb, protoff, -1, &_frag_off);
-               if (protohdr < 0)
+               if (protohdr < 0) {
+                       if (_frag_off == 0)
+                               *hotdrop = 1;
                        return 0;
-
+               }
                *fragoff = _frag_off;
 
                dprintf("Packet protocol %hi ?= %s%hi.\n",
@@ -320,7 +322,7 @@ ip6t_do_table(struct sk_buff **pskb,
                IP_NF_ASSERT(e);
                IP_NF_ASSERT(back);
                if (ip6_packet_match(*pskb, indev, outdev, &e->ipv6,
-                       &protoff, &offset)) {
+                       &protoff, &offset, &hotdrop)) {
                        struct ip6t_entry_target *t;
 
                        if (IP6T_MATCH_ITERATE(e, do_match,