From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753497AbcHUT6M (ORCPT ); Sun, 21 Aug 2016 15:58:12 -0400 Received: from wtarreau.pck.nerim.net ([62.212.114.60]:56736 "EHLO 1wt.eu" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752602AbcHUT6J (ORCPT ); Sun, 21 Aug 2016 15:58:09 -0400 Date: Sun, 21 Aug 2016 21:57:52 +0200 From: Willy Tarreau To: linux-kernel@vger.kernel.org, stable@vger.kernel.org Cc: Florian Westphal , Pablo Neira Ayuso , Jay Subject: Re: [PATCH 3.10 007/180] netfilter: x_tables: validate targets of jumps Message-ID: <20160821195752.GA21254@1wt.eu> References: <1471793510-13022-1-git-send-email-w@1wt.eu> <1471793510-13022-8-git-send-email-w@1wt.eu> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <1471793510-13022-8-git-send-email-w@1wt.eu> User-Agent: Mutt/1.6.0 (2016-04-01) Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On Sun, Aug 21, 2016 at 05:28:57PM +0200, Willy Tarreau wrote: > From: Florian Westphal > > commit 36472341017529e2b12573093cc0f68719300997 upstream. > > When we see a jump also check that the offset gets us to beginning of > a rule (an ipt_entry). (...) Sorry, this patch is bad and causes performance issues, I didn't notice that 3.14 had a different version, below. Thanks to Jay for reporting the problem to me. I'll push 3.10.103-rc2 after some cool down period. Willy ---- >>From 3c079e0993ca3bdd94dddd028ee04c85911aa666 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Fri, 1 Apr 2016 14:17:22 +0200 Subject: netfilter: x_tables: validate targets of jumps commit 36472341017529e2b12573093cc0f68719300997 upstream. When we see a jump also check that the offset gets us to beginning of a rule (an ipt_entry). The extra overhead is negible, even with absurd cases. 300k custom rules, 300k jumps to 'next' user chain: [ plus one jump from INPUT to first userchain ]: Before: real 0m24.874s user 0m7.532s sys 0m16.076s After: real 0m27.464s user 0m7.436s sys 0m18.840s Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso [wt: pick the patch from 3.14, it slightly differs to address the issue described here : https://patchwork.ozlabs.org/patch/650121/] Signed-off-by: Willy Tarreau --- net/ipv4/netfilter/arp_tables.c | 17 +++++++++++++++++ net/ipv4/netfilter/ip_tables.c | 17 +++++++++++++++++ net/ipv6/netfilter/ip6_tables.c | 17 +++++++++++++++++ 3 files changed, 51 insertions(+) diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c index 7460b7b..473ec55 100644 --- a/net/ipv4/netfilter/arp_tables.c +++ b/net/ipv4/netfilter/arp_tables.c @@ -358,6 +358,19 @@ static inline bool unconditional(const struct arpt_entry *e) memcmp(&e->arp, &uncond, sizeof(uncond)) == 0; } +static bool find_jump_target(const struct xt_table_info *t, + const void *entry0, + const struct arpt_entry *target) +{ + struct arpt_entry *iter; + + xt_entry_foreach(iter, entry0, t->size) { + if (iter == target) + return true; + } + return false; +} + /* Figures out from what hook each rule can be called: returns 0 if * there are loops. Puts hook bitmask in comefrom. */ @@ -451,6 +464,10 @@ static int mark_source_chains(const struct xt_table_info *newinfo, /* This a jump; chase it. */ duprintf("Jump rule %u -> %u\n", pos, newpos); + e = (struct arpt_entry *) + (entry0 + newpos); + if (!find_jump_target(newinfo, entry0, e)) + return 0; } else { /* ... this is a fallthru */ newpos = pos + e->next_offset; diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index 8fc22ee..dba9d80 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c @@ -434,6 +434,19 @@ ipt_do_table(struct sk_buff *skb, #endif } +static bool find_jump_target(const struct xt_table_info *t, + const void *entry0, + const struct ipt_entry *target) +{ + struct ipt_entry *iter; + + xt_entry_foreach(iter, entry0, t->size) { + if (iter == target) + return true; + } + return false; +} + /* Figures out from what hook each rule can be called: returns 0 if there are loops. Puts hook bitmask in comefrom. */ static int @@ -531,6 +544,10 @@ mark_source_chains(const struct xt_table_info *newinfo, /* This a jump; chase it. */ duprintf("Jump rule %u -> %u\n", pos, newpos); + e = (struct ipt_entry *) + (entry0 + newpos); + if (!find_jump_target(newinfo, entry0, e)) + return 0; } else { /* ... this is a fallthru */ newpos = pos + e->next_offset; diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index 63f7876..97a8d25 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c @@ -444,6 +444,19 @@ ip6t_do_table(struct sk_buff *skb, #endif } +static bool find_jump_target(const struct xt_table_info *t, + const void *entry0, + const struct ip6t_entry *target) +{ + struct ip6t_entry *iter; + + xt_entry_foreach(iter, entry0, t->size) { + if (iter == target) + return true; + } + return false; +} + /* Figures out from what hook each rule can be called: returns 0 if there are loops. Puts hook bitmask in comefrom. */ static int @@ -541,6 +554,10 @@ mark_source_chains(const struct xt_table_info *newinfo, /* This a jump; chase it. */ duprintf("Jump rule %u -> %u\n", pos, newpos); + e = (struct ip6t_entry *) + (entry0 + newpos); + if (!find_jump_target(newinfo, entry0, e)) + return 0; } else { /* ... this is a fallthru */ newpos = pos + e->next_offset; -- 2.8.0.rc2.1.gbe9624a