Author: dannf
Date: Mon Dec 18 01:26:17 2006
New Revision: 8024

Added:
   
dists/sid/linux-2.6/debian/patches/bugfix/ip6_tables-extension-header-bypass-bug.patch
   
dists/sid/linux-2.6/debian/patches/bugfix/ip6_tables-protocol-bypass-bug.patch
Modified:
   dists/sid/linux-2.6/debian/changelog
   dists/sid/linux-2.6/debian/patches/series/9
Log:
* Fix potential fragmentation attacks in ip6_tables (CVE-2006-4572)

Modified: dists/sid/linux-2.6/debian/changelog
==============================================================================
--- dists/sid/linux-2.6/debian/changelog        (original)
+++ dists/sid/linux-2.6/debian/changelog        Mon Dec 18 01:26:17 2006
@@ -11,8 +11,9 @@
 
   [ dann frazier ]
   * Fix data corruption with dm-crypt over RAID5 (closes: #402812)
+  * Fix potential fragmentation attacks in ip6_tables (CVE-2006-4572)
 
- -- dann frazier <[EMAIL PROTECTED]>  Tue, 12 Dec 2006 13:38:26 -0700
+ -- dann frazier <[EMAIL PROTECTED]>  Sun, 17 Dec 2006 17:18:20 -0700
 
 linux-2.6 (2.6.18-8) unstable; urgency=low
 

Added: 
dists/sid/linux-2.6/debian/patches/bugfix/ip6_tables-extension-header-bypass-bug.patch
==============================================================================
--- (empty file)
+++ 
dists/sid/linux-2.6/debian/patches/bugfix/ip6_tables-extension-header-bypass-bug.patch
      Mon Dec 18 01:26:17 2006
@@ -0,0 +1,157 @@
+From: Patrick McHardy <[EMAIL PROTECTED]>
+Date: Tue, 24 Oct 2006 23:15:10 +0000 (-0700)
+Subject: [NETFILTER]: Fix ip6_tables extension header bypass bug
+X-Git-Tag: v2.6.19-rc4
+X-Git-Url: 
http://www.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=6d381634d213580d40d431e7664dfb45f641b884
+
+[NETFILTER]: Fix ip6_tables extension header bypass bug
+
+As reported by Mark Dowd <[EMAIL PROTECTED]>, ip6_tables is susceptible
+to a fragmentation attack causing false negatives on extension header matches.
+
+When extension headers occur in the non-first fragment after the fragment
+header (possibly with an incorrect nexthdr value in the fragment header)
+a rule looking for this extension header 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.
+Since all extension headers are before the protocol header this makes sure
+an extension header is either not present or in the first fragment, where
+we can properly parse it.
+
+With help from Yasuyuki KOZAKAI <[EMAIL PROTECTED]>.
+
+Signed-off-by: Patrick McHardy <[EMAIL PROTECTED]>
+Signed-off-by: David S. Miller <[EMAIL PROTECTED]>
+---
+
+Backported to Debian's 2.6.18 by dann frazier <[EMAIL PROTECTED]>
+
+---
+diff -urN linux-source-2.6.18.orig/net/ipv6/netfilter/ip6_tables.c 
linux-source-2.6.18/net/ipv6/netfilter/ip6_tables.c
+--- linux-source-2.6.18.orig/net/ipv6/netfilter/ip6_tables.c   2006-12-17 
17:04:11.676261000 -0700
++++ linux-source-2.6.18/net/ipv6/netfilter/ip6_tables.c        2006-12-17 
17:04:47.298488000 -0700
+@@ -1447,6 +1447,9 @@
+  * If target header is found, its offset is set in *offset and return protocol
+  * number. Otherwise, return -1.
+  *
++ * If the first fragment doesn't contain the final protocol header or
++ * NEXTHDR_NONE it is considered invalid.
++ *
+  * Note that non-1st fragment is special case that "the protocol number
+  * of last header" is "next header" field in Fragment header. In this case,
+  * *offset is meaningless and fragment offset is stored in *fragoff if fragoff
+@@ -1470,12 +1473,12 @@
+               if ((!ipv6_ext_hdr(nexthdr)) || nexthdr == NEXTHDR_NONE) {
+                       if (target < 0)
+                               break;
+-                      return -1;
++                      return -ENOENT;
+               }
+ 
+               hp = skb_header_pointer(skb, start, sizeof(_hdr), &_hdr);
+               if (hp == NULL)
+-                      return -1;
++                      return -EBADMSG;
+               if (nexthdr == NEXTHDR_FRAGMENT) {
+                       unsigned short _frag_off, *fp;
+                       fp = skb_header_pointer(skb,
+@@ -1484,7 +1487,7 @@
+                                               sizeof(_frag_off),
+                                               &_frag_off);
+                       if (fp == NULL)
+-                              return -1;
++                              return -EBADMSG;
+ 
+                       _frag_off = ntohs(*fp) & ~0x7;
+                       if (_frag_off) {
+@@ -1495,7 +1498,7 @@
+                                               *fragoff = _frag_off;
+                                       return hp->nexthdr;
+                               }
+-                              return -1;
++                              return -ENOENT;
+                       }
+                       hdrlen = 8;
+               } else if (nexthdr == NEXTHDR_AUTH)
+diff -urN linux-source-2.6.18.orig/net/ipv6/netfilter/ip6t_ah.c 
linux-source-2.6.18/net/ipv6/netfilter/ip6t_ah.c
+--- linux-source-2.6.18.orig/net/ipv6/netfilter/ip6t_ah.c      2006-09-19 
21:42:06.000000000 -0600
++++ linux-source-2.6.18/net/ipv6/netfilter/ip6t_ah.c   2006-12-17 
17:04:47.302488250 -0700
+@@ -54,9 +54,14 @@
+       const struct ip6t_ah *ahinfo = matchinfo;
+       unsigned int ptr;
+       unsigned int hdrlen = 0;
++      int err;
+ 
+-      if (ipv6_find_hdr(skb, &ptr, NEXTHDR_AUTH, NULL) < 0)
++      err = ipv6_find_hdr(skb, &ptr, NEXTHDR_AUTH, NULL);
++      if (err < 0) {
++              if (err != -ENOENT)
++                      *hotdrop = 1;
+               return 0;
++      }
+ 
+       ah = skb_header_pointer(skb, ptr, sizeof(_ah), &_ah);
+       if (ah == NULL) {
+diff -urN linux-source-2.6.18.orig/net/ipv6/netfilter/ip6t_frag.c 
linux-source-2.6.18/net/ipv6/netfilter/ip6t_frag.c
+--- linux-source-2.6.18.orig/net/ipv6/netfilter/ip6t_frag.c    2006-09-19 
21:42:06.000000000 -0600
++++ linux-source-2.6.18/net/ipv6/netfilter/ip6t_frag.c 2006-12-17 
17:04:47.302488250 -0700
+@@ -52,9 +52,14 @@
+       struct frag_hdr _frag, *fh;
+       const struct ip6t_frag *fraginfo = matchinfo;
+       unsigned int ptr;
++      int err;
+ 
+-      if (ipv6_find_hdr(skb, &ptr, NEXTHDR_FRAGMENT, NULL) < 0)
++      err = ipv6_find_hdr(skb, &ptr, NEXTHDR_FRAGMENT, NULL);
++      if (err < 0) {
++              if (err != -ENOENT)
++                      *hotdrop = 1;
+               return 0;
++      }
+ 
+       fh = skb_header_pointer(skb, ptr, sizeof(_frag), &_frag);
+       if (fh == NULL) {
+diff -urN linux-source-2.6.18.orig/net/ipv6/netfilter/ip6t_hbh.c 
linux-source-2.6.18/net/ipv6/netfilter/ip6t_hbh.c
+--- linux-source-2.6.18.orig/net/ipv6/netfilter/ip6t_hbh.c     2006-09-19 
21:42:06.000000000 -0600
++++ linux-source-2.6.18/net/ipv6/netfilter/ip6t_hbh.c  2006-12-17 
17:12:20.758827500 -0700
+@@ -70,13 +70,18 @@
+       u8 _opttype, *tp = NULL;
+       u8 _optlen, *lp = NULL;
+       unsigned int optlen;
++      int err;
+ 
+ #if HOPBYHOP
+-      if (ipv6_find_hdr(skb, &ptr, NEXTHDR_HOP, NULL) < 0)
++      err = ipv6_find_hdr(skb, &ptr, NEXTHDR_HOP, NULL);
+ #else
+-      if (ipv6_find_hdr(skb, &ptr, NEXTHDR_DEST, NULL) < 0)
++      err = ipv6_find_hdr(skb, &ptr, NEXTHDR_DEST, NULL;
+ #endif
++      if (err < 0) {
++              if (err != -ENOENT)
++                      *hotdrop = 1;
+               return 0;
++      }
+ 
+       oh = skb_header_pointer(skb, ptr, sizeof(_optsh), &_optsh);
+       if (oh == NULL) {
+diff -urN linux-source-2.6.18.orig/net/ipv6/netfilter/ip6t_rt.c 
linux-source-2.6.18/net/ipv6/netfilter/ip6t_rt.c
+--- linux-source-2.6.18.orig/net/ipv6/netfilter/ip6t_rt.c      2006-09-19 
21:42:06.000000000 -0600
++++ linux-source-2.6.18/net/ipv6/netfilter/ip6t_rt.c   2006-12-17 
17:04:47.302488250 -0700
+@@ -58,9 +58,14 @@
+       unsigned int hdrlen = 0;
+       unsigned int ret = 0;
+       struct in6_addr *ap, _addr;
++      int err;
+ 
+-      if (ipv6_find_hdr(skb, &ptr, NEXTHDR_ROUTING, NULL) < 0)
++      err = ipv6_find_hdr(skb, &ptr, NEXTHDR_ROUTING, NULL);
++      if (err < 0) {
++              if (err != -ENOENT)
++                      *hotdrop = 1;
+               return 0;
++      }
+ 
+       rh = skb_header_pointer(skb, ptr, sizeof(_route), &_route);
+       if (rh == NULL) {

Added: 
dists/sid/linux-2.6/debian/patches/bugfix/ip6_tables-protocol-bypass-bug.patch
==============================================================================
--- (empty file)
+++ 
dists/sid/linux-2.6/debian/patches/bugfix/ip6_tables-protocol-bypass-bug.patch  
    Mon Dec 18 01:26:17 2006
@@ -0,0 +1,60 @@
+From: Patrick McHardy <[EMAIL PROTECTED]>
+Date: Tue, 24 Oct 2006 23:14:04 +0000 (-0700)
+Subject: [NETFILTER]: Fix ip6_tables protocol bypass bug
+X-Git-Tag: v2.6.19-rc4
+X-Git-Url: 
http://www.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=51d8b1a65291a6956b79374b6adbbadc2263bcf6
+
+[NETFILTER]: Fix ip6_tables protocol bypass bug
+
+As reported by Mark Dowd <[EMAIL PROTECTED]>, 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 <[EMAIL PROTECTED]>.
+
+Signed-off-by: Patrick McHardy <[EMAIL PROTECTED]>
+Signed-off-by: David S. Miller <[EMAIL PROTECTED]>
+---
+
+--- a/net/ipv6/netfilter/ip6_tables.c
++++ b/net/ipv6/netfilter/ip6_tables.c
+@@ -111,7 +111,7 @@ ip6_packet_match(const struct sk_buff *s
+                const char *outdev,
+                const struct ip6t_ip6 *ip6info,
+                unsigned int *protoff,
+-               int *fragoff)
++               int *fragoff, int *hotdrop)
+ {
+       size_t i;
+       unsigned long ret;
+@@ -169,9 +169,11 @@ ip6_packet_match(const struct sk_buff *s
+               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",
+@@ -290,7 +292,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,

Modified: dists/sid/linux-2.6/debian/patches/series/9
==============================================================================
--- dists/sid/linux-2.6/debian/patches/series/9 (original)
+++ dists/sid/linux-2.6/debian/patches/series/9 Mon Dec 18 01:26:17 2006
@@ -1,2 +1,4 @@
 + bugfix/dm-crypt-fix-data-corruption-with-dm-crypt-over-raid5.patch
 - bugfix/2.6.18.5-revert-abi-1.patch
+bugfix/ip6_tables-protocol-bypass-bug.patch
+bugfix/ip6_tables-extension-header-bypass-bug.patch

_______________________________________________
Kernel-svn-changes mailing list
[email protected]
http://lists.alioth.debian.org/mailman/listinfo/kernel-svn-changes

Reply via email to