diff --git a/debian/changelog b/debian/changelog index 9304452c9..c0299aab3 100644 --- a/debian/changelog +++ b/debian/changelog @@ -26,8 +26,9 @@ linux-2.6 (2.6.18-4) UNRELEASED; urgency=low * Bump build-dependency on kernel-package to 10.063. * [sparc64] Add davem fix memory corruption in pci_4u_free_consistent(). * [sparc64] Add davem fix central/FHC bus handling on Ex000 systems. + * [ip6_tables] Add patches for protocol and extension header bypass bug. - -- maximilian attems Thu, 26 Oct 2006 21:58:59 +0200 + -- maximilian attems Thu, 26 Oct 2006 22:20:34 +0200 linux-2.6 (2.6.18-3) unstable; urgency=low diff --git a/debian/patches/bugfix/net-ip6_tables_extension_header-bypass.patch b/debian/patches/bugfix/net-ip6_tables_extension_header-bypass.patch new file mode 100644 index 000000000..d07d02e82 --- /dev/null +++ b/debian/patches/bugfix/net-ip6_tables_extension_header-bypass.patch @@ -0,0 +1,174 @@ +From git-commits-head-owner@vger.kernel.org Wed Oct 25 14:13:09 2006 +Date: Wed, 25 Oct 2006 05:59:05 GMT +Message-Id: <200610250559.k9P5x5tk014073@hera.kernel.org> +From: Linux Kernel Mailing List +To: git-commits-head@vger.kernel.org +Subject: [NETFILTER]: Fix ip6_tables extension header bypass bug + +commit 6d381634d213580d40d431e7664dfb45f641b884 +tree a8680dd059e9a4e115d17e54d4a8dcea4d196a3e +parent 51d8b1a65291a6956b79374b6adbbadc2263bcf6 +author Patrick McHardy 1161731710 -0700 +committer David S. Miller 1161731710 -0700 + +[NETFILTER]: Fix ip6_tables extension header bypass bug + +As reported by Mark Dowd , 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 . +Fixed reject in ip6t_hbh.c for stable. -maks + +Signed-off-by: Patrick McHardy +Signed-off-by: David S. Miller +Signed-off-by: maximilian attems + + net/ipv6/netfilter/ip6_tables.c | 11 +++++++---- + net/ipv6/netfilter/ip6t_ah.c | 7 ++++++- + net/ipv6/netfilter/ip6t_frag.c | 7 ++++++- + net/ipv6/netfilter/ip6t_hbh.c | 7 ++++++- + net/ipv6/netfilter/ip6t_rt.c | 7 ++++++- + 5 files changed, 31 insertions(+), 8 deletions(-) + +diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c +index f0328c7..53bf977 100644 +--- a/net/ipv6/netfilter/ip6_tables.c ++++ b/net/ipv6/netfilter/ip6_tables.c +@@ -1440,6 +1440,9 @@ static void __exit ip6_tables_fini(void) + * 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 +@@ -1463,12 +1466,12 @@ int ipv6_find_hdr(const struct sk_buff * + 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, +@@ -1477,7 +1480,7 @@ int ipv6_find_hdr(const struct sk_buff * + sizeof(_frag_off), + &_frag_off); + if (fp == NULL) +- return -1; ++ return -EBADMSG; + + _frag_off = ntohs(*fp) & ~0x7; + if (_frag_off) { +@@ -1488,7 +1491,7 @@ int ipv6_find_hdr(const struct sk_buff * + *fragoff = _frag_off; + return hp->nexthdr; + } +- return -1; ++ return -ENOENT; + } + hdrlen = 8; + } else if (nexthdr == NEXTHDR_AUTH) +diff --git a/net/ipv6/netfilter/ip6t_ah.c b/net/ipv6/netfilter/ip6t_ah.c +index ec1b160..4648664 100644 +--- a/net/ipv6/netfilter/ip6t_ah.c ++++ b/net/ipv6/netfilter/ip6t_ah.c +@@ -54,9 +54,14 @@ match(const struct sk_buff *skb, + 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 --git a/net/ipv6/netfilter/ip6t_frag.c b/net/ipv6/netfilter/ip6t_frag.c +index 78d9c8b..cd22eaa 100644 +--- a/net/ipv6/netfilter/ip6t_frag.c ++++ b/net/ipv6/netfilter/ip6t_frag.c +@@ -52,9 +52,14 @@ match(const struct sk_buff *skb, + 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) { +--- a/net/ipv6/netfilter/ip6t_hbh.c.orig 2006-10-26 22:11:31.000000000 +0200 ++++ b/net/ipv6/netfilter/ip6t_hbh.c 2006-10-26 22:13:06.000000000 +0200 +@@ -72,11 +72,15 @@ match(const struct sk_buff *skb, + unsigned int optlen; + + #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 --git a/net/ipv6/netfilter/ip6t_rt.c b/net/ipv6/netfilter/ip6t_rt.c +index bcb2e16..54d7d14 100644 +--- a/net/ipv6/netfilter/ip6t_rt.c ++++ b/net/ipv6/netfilter/ip6t_rt.c +@@ -58,9 +58,14 @@ match(const struct sk_buff *skb, + 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) { +- +To unsubscribe from this list: send the line "unsubscribe git-commits-head" in +the body of a message to majordomo@vger.kernel.org +More majordomo info at http://vger.kernel.org/majordomo-info.html + diff --git a/debian/patches/bugfix/net-ip6_tables_protocol-bypass.patch b/debian/patches/bugfix/net-ip6_tables_protocol-bypass.patch new file mode 100644 index 000000000..3d50b8e9d --- /dev/null +++ b/debian/patches/bugfix/net-ip6_tables_protocol-bypass.patch @@ -0,0 +1,75 @@ +From git-commits-head-owner@vger.kernel.org Tue Jun 6 18:56:24 2006 +Message-Id: <200610250559.k9P5x4BG014065@hera.kernel.org> +From: Linux Kernel Mailing List +To: git-commits-head@vger.kernel.org +Subject: [NETFILTER]: Fix ip6_tables protocol bypass bug + +commit 51d8b1a65291a6956b79374b6adbbadc2263bcf6 +tree d6b8cbd6628c11d1c3e9c8c8e9ca048acf723a71 +parent 2fab22f2d3290ff7c602fe62f22e825c48e97a06 +author Patrick McHardy 1161731644 -0700 +committer David S. Miller 1161731644 -0700 + +[NETFILTER]: Fix ip6_tables protocol bypass bug + +As reported by Mark Dowd , 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 . + +Signed-off-by: Patrick McHardy +Signed-off-by: David S. Miller + + net/ipv6/netfilter/ip6_tables.c | 10 ++++++---- + 1 file changed, 6 insertions(+), 4 deletions(-) + +diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c +index 4ab368f..f0328c7 100644 +--- 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 @@ #define FWINV(bool,invflg) ((bool) ^ !!( + 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, +- +To unsubscribe from this list: send the line "unsubscribe git-commits-head" in +the body of a message to majordomo@vger.kernel.org +More majordomo info at http://vger.kernel.org/majordomo-info.html + diff --git a/debian/patches/series/4 b/debian/patches/series/4 index d4eeb3ad6..17f67eabc 100644 --- a/debian/patches/series/4 +++ b/debian/patches/series/4 @@ -9,3 +9,5 @@ + bugfix/net-r8169-hotplug_loop.patch + bugfix/sparc/mem_corruption-pci_4u_free_consistent.patch + bugfix/sparc/central_fhc_bus-Ex000.patch ++ bugfix/net-ip6_tables_extension_header-bypass.patch ++ bugfix/net-ip6_tables_protocol-bypass.patch