aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPatrick McHardy <kaber@trash.net>2006-10-24 19:14:04 -0400
committerDavid S. Miller <davem@davemloft.net>2006-10-24 19:14:04 -0400
commit51d8b1a65291a6956b79374b6adbbadc2263bcf6 (patch)
treed6b8cbd6628c11d1c3e9c8c8e9ca048acf723a71
parent2fab22f2d3290ff7c602fe62f22e825c48e97a06 (diff)
[NETFILTER]: Fix ip6_tables protocol bypass bug
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: David S. Miller <davem@davemloft.net>
-rw-r--r--net/ipv6/netfilter/ip6_tables.c10
1 files changed, 6 insertions, 4 deletions
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c
index 4ab368fa0b8..f0328c7bc1c 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 *skb,
111 const char *outdev, 111 const char *outdev,
112 const struct ip6t_ip6 *ip6info, 112 const struct ip6t_ip6 *ip6info,
113 unsigned int *protoff, 113 unsigned int *protoff,
114 int *fragoff) 114 int *fragoff, int *hotdrop)
115{ 115{
116 size_t i; 116 size_t i;
117 unsigned long ret; 117 unsigned long ret;
@@ -169,9 +169,11 @@ ip6_packet_match(const struct sk_buff *skb,
169 unsigned short _frag_off; 169 unsigned short _frag_off;
170 170
171 protohdr = ipv6_find_hdr(skb, protoff, -1, &_frag_off); 171 protohdr = ipv6_find_hdr(skb, protoff, -1, &_frag_off);
172 if (protohdr < 0) 172 if (protohdr < 0) {
173 if (_frag_off == 0)
174 *hotdrop = 1;
173 return 0; 175 return 0;
174 176 }
175 *fragoff = _frag_off; 177 *fragoff = _frag_off;
176 178
177 dprintf("Packet protocol %hi ?= %s%hi.\n", 179 dprintf("Packet protocol %hi ?= %s%hi.\n",
@@ -290,7 +292,7 @@ ip6t_do_table(struct sk_buff **pskb,
290 IP_NF_ASSERT(e); 292 IP_NF_ASSERT(e);
291 IP_NF_ASSERT(back); 293 IP_NF_ASSERT(back);
292 if (ip6_packet_match(*pskb, indev, outdev, &e->ipv6, 294 if (ip6_packet_match(*pskb, indev, outdev, &e->ipv6,
293 &protoff, &offset)) { 295 &protoff, &offset, &hotdrop)) {
294 struct ip6t_entry_target *t; 296 struct ip6t_entry_target *t;
295 297
296 if (IP6T_MATCH_ITERATE(e, do_match, 298 if (IP6T_MATCH_ITERATE(e, do_match,