* Re: [PATCH v2] KEYS: DNS: limit the length of option strings
From: Eric Biggers @ 2018-03-12 17:57 UTC (permalink / raw)
To: David Howells; +Cc: keyrings, netdev, Mark Rutland, Eric Biggers
In-Reply-To: <31292.1520438077@warthog.procyon.org.uk>
On Wed, Mar 07, 2018 at 03:54:37PM +0000, David Howells wrote:
> Eric Biggers <ebiggers3@gmail.com> wrote:
>
> > Fix it by limiting option strings (combined name + value) to a much more
> > reasonable 128 bytes. The exact limit is arbitrary, but currently the
> > only recognized option is formatted as "dnserror=%lu" which fits well
> > within this limit.
>
> There will be more options coming ("ipv4", "ipv6") but they shouldn't overrun
> this limit and we can always extend the limit if need be.
>
> David
David (Howells) do you want to take this patch through the keyrings tree or
should I ask David Miller to take it through net-next?
Eric
^ permalink raw reply
* [PATCH 00/30] Netfilter/IPVS updates for net-next
From: Pablo Neira Ayuso @ 2018-03-12 17:58 UTC (permalink / raw)
To: netfilter-devel; +Cc: davem, netdev
Hi David,
The following patchset contains Netfilter/IPVS updates for your net-next
tree. This batch comes with more input sanitization for xtables to
address bug reports from fuzzers, preparation works to the flowtable
infrastructure and assorted updates. In no particular order, they are:
1) Make sure userspace provides a valid standard target verdict, from
Florian Westphal.
2) Sanitize error target size, also from Florian.
3) Validate that last rule in basechain matches underflow/policy since
userspace assumes this when decoding the ruleset blob that comes
from the kernel, from Florian.
4) Consolidate hook entry checks through xt_check_table_hooks(),
patch from Florian.
5) Cap ruleset allocations at 512 mbytes, 134217728 rules and reject
very large compat offset arrays, so we have a reasonable upper limit
and fuzzers don't exercise the oom-killer. Patches from Florian.
6) Several WARN_ON checks on xtables mutex helper, from Florian.
7) xt_rateest now has a hashtable per net, from Cong Wang.
8) Consolidate counter allocation in xt_counters_alloc(), from Florian.
9) Earlier xt_table_unlock() call in {ip,ip6,arp,eb}tables, patch
from Xin Long.
10) Set FLOW_OFFLOAD_DIR_* to IP_CT_DIR_* definitions, patch from
Felix Fietkau.
11) Consolidate code through flow_offload_fill_dir(), also from Felix.
12) Inline ip6_dst_mtu_forward() just like ip_dst_mtu_maybe_forward()
to remove a dependency with flowtable and ipv6.ko, from Felix.
13) Cache mtu size in flow_offload_tuple object, this is safe for
forwarding as f87c10a8aa1e describes, from Felix.
14) Rename nf_flow_table.c to nf_flow_table_core.o, to simplify too
modular infrastructure, from Felix.
15) Add rt0, rt2 and rt4 IPv6 routing extension support, patch from
Ahmed Abdelsalam.
16) Remove unused parameter in nf_conncount_count(), from Yi-Hung Wei.
17) Support for counting only to nf_conncount infrastructure, patch
from Yi-Hung Wei.
18) Add strict NFT_CT_{SRC_IP,DST_IP,SRC_IP6,DST_IP6} key datatypes
to nft_ct.
19) Use boolean as return value from ipt_ah and from IPVS too, patch
from Gustavo A. R. Silva.
20) Remove useless parameters in nfnl_acct_overquota() and
nf_conntrack_broadcast_help(), from Taehee Yoo.
21) Use ipv6_addr_is_multicast() from xt_cluster, also from Taehee Yoo.
22) Statify nf_tables_obj_lookup_byhandle, patch from Fengguang Wu.
23) Fix typo in xt_limit, from Geert Uytterhoeven.
You can pull these changes from:
git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf-next.git
Thanks!
----------------------------------------------------------------
The following changes since commit ef3f6c256f0b4711a3ef1489797b95820be5ab01:
Merge branch 'mvpp2-jumbo-frames-support' (2018-03-05 12:55:55 -0500)
are available in the git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf-next.git HEAD
for you to fetch changes up to 90eee0957b655339d659c0b9bba64f5c90b2233b:
netfilter: nft_ct: add NFT_CT_{SRC,DST}_{IP,IP6} (2018-03-11 22:17:57 +0100)
----------------------------------------------------------------
Ahmed Abdelsalam (1):
netfilter: nf_tables: handle rt0 and rt2 properly
Cong Wang (1):
netfilter: make xt_rateest hash table per net
Felix Fietkau (5):
netfilter: nf_flow_table: use IP_CT_DIR_* values for FLOW_OFFLOAD_DIR_*
netfilter: nf_flow_table: clean up flow_offload_alloc
ipv6: make ip6_dst_mtu_forward inline
netfilter: nf_flow_table: cache mtu in struct flow_offload_tuple
netfilter: nf_flow_table: rename nf_flow_table.c to nf_flow_table_core.c
Florian Westphal (12):
netfilter: x_tables: check standard verdicts in core
netfilter: x_tables: check error target size too
netfilter: x_tables: move hook entry checks into core
netfilter: x_tables: enforce unique and ascending entry points
netfilter: x_tables: cap allocations at 512 mbyte
netfilter: x_tables: limit allocation requests for blob rule heads
netfilter: x_tables: add counters allocation wrapper
netfilter: compat: prepare xt_compat_init_offsets to return errors
netfilter: compat: reject huge allocation requests
netfilter: x_tables: make sure compat af mutex is held
netfilter: x_tables: ensure last rule in base chain matches underflow/policy
netfilter: x_tables: fix build with CONFIG_COMPAT=n
Geert Uytterhoeven (1):
netfilter: xt_limit: Spelling s/maxmum/maximum/
Gustavo A. R. Silva (2):
netfilter: ipt_ah: return boolean instead of integer
ipvs: use true and false for boolean values
Pablo Neira Ayuso (1):
netfilter: nft_ct: add NFT_CT_{SRC,DST}_{IP,IP6}
Taehee Yoo (3):
netfilter: nfnetlink_acct: remove useless parameter
netfilter: xt_cluster: get rid of xt_cluster_ipv6_is_multicast
netfilter: nf_conntrack_broadcast: remove useless parameter
Xin Long (1):
netfilter: unlock xt_table earlier in __do_replace
Yi-Hung Wei (2):
netfilter: Refactor nf_conncount
netfilter: conncount: Support count only use case
kbuild test robot (1):
netfilter: nf_tables: nf_tables_obj_lookup_byhandle() can be static
include/linux/netfilter/nfnetlink_acct.h | 3 +-
include/linux/netfilter/x_tables.h | 5 +-
include/net/ip6_route.h | 21 +++
include/net/ipv6.h | 2 -
include/net/netfilter/nf_conntrack_count.h | 1 -
include/net/netfilter/nf_conntrack_helper.h | 3 +-
include/net/netfilter/nf_flow_table.h | 10 +-
include/net/netfilter/xt_rateest.h | 4 +-
include/uapi/linux/netfilter/nf_tables.h | 15 +-
net/bridge/netfilter/ebtables.c | 10 +-
net/ipv4/netfilter/arp_tables.c | 50 +++---
net/ipv4/netfilter/ip_tables.c | 48 +++---
net/ipv4/netfilter/ipt_ah.c | 2 +-
net/ipv4/netfilter/nf_flow_table_ipv4.c | 17 +-
net/ipv6/ip6_output.c | 22 ---
net/ipv6/netfilter/ip6_tables.c | 50 +++---
net/ipv6/netfilter/nf_flow_table_ipv6.c | 17 +-
net/netfilter/Makefile | 2 +
net/netfilter/ipvs/ip_vs_lblc.c | 4 +-
net/netfilter/ipvs/ip_vs_lblcr.c | 4 +-
net/netfilter/nf_conncount.c | 14 +-
net/netfilter/nf_conntrack_broadcast.c | 1 -
net/netfilter/nf_conntrack_netbios_ns.c | 5 +-
net/netfilter/nf_conntrack_snmp.c | 5 +-
.../{nf_flow_table.c => nf_flow_table_core.c} | 97 +++++------
net/netfilter/nf_tables_api.c | 8 +-
net/netfilter/nfnetlink_acct.c | 3 +-
net/netfilter/nft_ct.c | 38 +++++
net/netfilter/nft_exthdr.c | 3 +
net/netfilter/x_tables.c | 187 +++++++++++++++++++--
net/netfilter/xt_RATEEST.c | 91 +++++++---
net/netfilter/xt_cluster.c | 10 +-
net/netfilter/xt_connlimit.c | 4 +-
net/netfilter/xt_limit.c | 2 +-
net/netfilter/xt_nfacct.c | 2 +-
net/netfilter/xt_rateest.c | 10 +-
36 files changed, 500 insertions(+), 270 deletions(-)
rename net/netfilter/{nf_flow_table.c => nf_flow_table_core.c} (79%)
^ permalink raw reply
* [PATCH 01/30] netfilter: nf_tables: nf_tables_obj_lookup_byhandle() can be static
From: Pablo Neira Ayuso @ 2018-03-12 17:58 UTC (permalink / raw)
To: netfilter-devel; +Cc: davem, netdev
In-Reply-To: <20180312175920.9022-1-pablo@netfilter.org>
From: kbuild test robot <fengguang.wu@intel.com>
Fixes: 3ecbfd65f50e ("netfilter: nf_tables: allocate handle and delete objects via handle")
Signed-off-by: Fengguang Wu <fengguang.wu@intel.com>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
net/netfilter/nf_tables_api.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
index 8b9fe30de0cd..8cc7fc970f0c 100644
--- a/net/netfilter/nf_tables_api.c
+++ b/net/netfilter/nf_tables_api.c
@@ -4328,9 +4328,9 @@ struct nft_object *nf_tables_obj_lookup(const struct nft_table *table,
}
EXPORT_SYMBOL_GPL(nf_tables_obj_lookup);
-struct nft_object *nf_tables_obj_lookup_byhandle(const struct nft_table *table,
- const struct nlattr *nla,
- u32 objtype, u8 genmask)
+static struct nft_object *nf_tables_obj_lookup_byhandle(const struct nft_table *table,
+ const struct nlattr *nla,
+ u32 objtype, u8 genmask)
{
struct nft_object *obj;
@@ -4850,7 +4850,7 @@ struct nft_flowtable *nf_tables_flowtable_lookup(const struct nft_table *table,
}
EXPORT_SYMBOL_GPL(nf_tables_flowtable_lookup);
-struct nft_flowtable *
+static struct nft_flowtable *
nf_tables_flowtable_lookup_byhandle(const struct nft_table *table,
const struct nlattr *nla, u8 genmask)
{
--
2.11.0
^ permalink raw reply related
* [PATCH 03/30] netfilter: xt_cluster: get rid of xt_cluster_ipv6_is_multicast
From: Pablo Neira Ayuso @ 2018-03-12 17:58 UTC (permalink / raw)
To: netfilter-devel; +Cc: davem, netdev
In-Reply-To: <20180312175920.9022-1-pablo@netfilter.org>
From: Taehee Yoo <ap420073@gmail.com>
If use the ipv6_addr_is_multicast instead of xt_cluster_ipv6_is_multicast,
then we can reduce code size.
Signed-off-by: Taehee Yoo <ap420073@gmail.com>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
net/netfilter/xt_cluster.c | 10 +---------
1 file changed, 1 insertion(+), 9 deletions(-)
diff --git a/net/netfilter/xt_cluster.c b/net/netfilter/xt_cluster.c
index 0068688995c8..dfbdbb2fc0ed 100644
--- a/net/netfilter/xt_cluster.c
+++ b/net/netfilter/xt_cluster.c
@@ -60,13 +60,6 @@ xt_cluster_hash(const struct nf_conn *ct,
}
static inline bool
-xt_cluster_ipv6_is_multicast(const struct in6_addr *addr)
-{
- __be32 st = addr->s6_addr32[0];
- return ((st & htonl(0xFF000000)) == htonl(0xFF000000));
-}
-
-static inline bool
xt_cluster_is_multicast_addr(const struct sk_buff *skb, u_int8_t family)
{
bool is_multicast = false;
@@ -76,8 +69,7 @@ xt_cluster_is_multicast_addr(const struct sk_buff *skb, u_int8_t family)
is_multicast = ipv4_is_multicast(ip_hdr(skb)->daddr);
break;
case NFPROTO_IPV6:
- is_multicast =
- xt_cluster_ipv6_is_multicast(&ipv6_hdr(skb)->daddr);
+ is_multicast = ipv6_addr_is_multicast(&ipv6_hdr(skb)->daddr);
break;
default:
WARN_ON(1);
--
2.11.0
^ permalink raw reply related
* [PATCH 02/30] netfilter: nfnetlink_acct: remove useless parameter
From: Pablo Neira Ayuso @ 2018-03-12 17:58 UTC (permalink / raw)
To: netfilter-devel; +Cc: davem, netdev
In-Reply-To: <20180312175920.9022-1-pablo@netfilter.org>
From: Taehee Yoo <ap420073@gmail.com>
parameter skb in nfnl_acct_overquota is not used anywhere.
Signed-off-by: Taehee Yoo <ap420073@gmail.com>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
include/linux/netfilter/nfnetlink_acct.h | 3 +--
net/netfilter/nfnetlink_acct.c | 3 +--
net/netfilter/xt_nfacct.c | 2 +-
3 files changed, 3 insertions(+), 5 deletions(-)
diff --git a/include/linux/netfilter/nfnetlink_acct.h b/include/linux/netfilter/nfnetlink_acct.h
index b4d741195c28..beee8bffe49e 100644
--- a/include/linux/netfilter/nfnetlink_acct.h
+++ b/include/linux/netfilter/nfnetlink_acct.h
@@ -16,6 +16,5 @@ struct nf_acct;
struct nf_acct *nfnl_acct_find_get(struct net *net, const char *filter_name);
void nfnl_acct_put(struct nf_acct *acct);
void nfnl_acct_update(const struct sk_buff *skb, struct nf_acct *nfacct);
-int nfnl_acct_overquota(struct net *net, const struct sk_buff *skb,
- struct nf_acct *nfacct);
+int nfnl_acct_overquota(struct net *net, struct nf_acct *nfacct);
#endif /* _NFNL_ACCT_H */
diff --git a/net/netfilter/nfnetlink_acct.c b/net/netfilter/nfnetlink_acct.c
index 88d427f9f9e6..b9505bcd3827 100644
--- a/net/netfilter/nfnetlink_acct.c
+++ b/net/netfilter/nfnetlink_acct.c
@@ -467,8 +467,7 @@ static void nfnl_overquota_report(struct net *net, struct nf_acct *nfacct)
GFP_ATOMIC);
}
-int nfnl_acct_overquota(struct net *net, const struct sk_buff *skb,
- struct nf_acct *nfacct)
+int nfnl_acct_overquota(struct net *net, struct nf_acct *nfacct)
{
u64 now;
u64 *quota;
diff --git a/net/netfilter/xt_nfacct.c b/net/netfilter/xt_nfacct.c
index c8674deed4eb..6b56f4170860 100644
--- a/net/netfilter/xt_nfacct.c
+++ b/net/netfilter/xt_nfacct.c
@@ -28,7 +28,7 @@ static bool nfacct_mt(const struct sk_buff *skb, struct xt_action_param *par)
nfnl_acct_update(skb, info->nfacct);
- overquota = nfnl_acct_overquota(xt_net(par), skb, info->nfacct);
+ overquota = nfnl_acct_overquota(xt_net(par), info->nfacct);
return overquota == NFACCT_UNDERQUOTA ? false : true;
}
--
2.11.0
^ permalink raw reply related
* [PATCH 04/30] netfilter: nf_conntrack_broadcast: remove useless parameter
From: Pablo Neira Ayuso @ 2018-03-12 17:58 UTC (permalink / raw)
To: netfilter-devel; +Cc: davem, netdev
In-Reply-To: <20180312175920.9022-1-pablo@netfilter.org>
From: Taehee Yoo <ap420073@gmail.com>
parameter protoff in nf_conntrack_broadcast_help is not used anywhere.
Signed-off-by: Taehee Yoo <ap420073@gmail.com>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
include/net/netfilter/nf_conntrack_helper.h | 3 +--
net/netfilter/nf_conntrack_broadcast.c | 1 -
net/netfilter/nf_conntrack_netbios_ns.c | 5 +++--
net/netfilter/nf_conntrack_snmp.c | 5 +++--
4 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/include/net/netfilter/nf_conntrack_helper.h b/include/net/netfilter/nf_conntrack_helper.h
index fc39bbaf107c..32c2a94a219d 100644
--- a/include/net/netfilter/nf_conntrack_helper.h
+++ b/include/net/netfilter/nf_conntrack_helper.h
@@ -132,8 +132,7 @@ void nf_conntrack_helper_pernet_fini(struct net *net);
int nf_conntrack_helper_init(void);
void nf_conntrack_helper_fini(void);
-int nf_conntrack_broadcast_help(struct sk_buff *skb, unsigned int protoff,
- struct nf_conn *ct,
+int nf_conntrack_broadcast_help(struct sk_buff *skb, struct nf_conn *ct,
enum ip_conntrack_info ctinfo,
unsigned int timeout);
diff --git a/net/netfilter/nf_conntrack_broadcast.c b/net/netfilter/nf_conntrack_broadcast.c
index ecc3ab784633..a1086bdec242 100644
--- a/net/netfilter/nf_conntrack_broadcast.c
+++ b/net/netfilter/nf_conntrack_broadcast.c
@@ -20,7 +20,6 @@
#include <net/netfilter/nf_conntrack_expect.h>
int nf_conntrack_broadcast_help(struct sk_buff *skb,
- unsigned int protoff,
struct nf_conn *ct,
enum ip_conntrack_info ctinfo,
unsigned int timeout)
diff --git a/net/netfilter/nf_conntrack_netbios_ns.c b/net/netfilter/nf_conntrack_netbios_ns.c
index 496ce173f0c1..a4a59dc7cf17 100644
--- a/net/netfilter/nf_conntrack_netbios_ns.c
+++ b/net/netfilter/nf_conntrack_netbios_ns.c
@@ -41,9 +41,10 @@ static struct nf_conntrack_expect_policy exp_policy = {
};
static int netbios_ns_help(struct sk_buff *skb, unsigned int protoff,
- struct nf_conn *ct, enum ip_conntrack_info ctinfo)
+ struct nf_conn *ct,
+ enum ip_conntrack_info ctinfo)
{
- return nf_conntrack_broadcast_help(skb, protoff, ct, ctinfo, timeout);
+ return nf_conntrack_broadcast_help(skb, ct, ctinfo, timeout);
}
static struct nf_conntrack_helper helper __read_mostly = {
diff --git a/net/netfilter/nf_conntrack_snmp.c b/net/netfilter/nf_conntrack_snmp.c
index 87b95a2c270c..2d0f8e010821 100644
--- a/net/netfilter/nf_conntrack_snmp.c
+++ b/net/netfilter/nf_conntrack_snmp.c
@@ -36,11 +36,12 @@ int (*nf_nat_snmp_hook)(struct sk_buff *skb,
EXPORT_SYMBOL_GPL(nf_nat_snmp_hook);
static int snmp_conntrack_help(struct sk_buff *skb, unsigned int protoff,
- struct nf_conn *ct, enum ip_conntrack_info ctinfo)
+ struct nf_conn *ct,
+ enum ip_conntrack_info ctinfo)
{
typeof(nf_nat_snmp_hook) nf_nat_snmp;
- nf_conntrack_broadcast_help(skb, protoff, ct, ctinfo, timeout);
+ nf_conntrack_broadcast_help(skb, ct, ctinfo, timeout);
nf_nat_snmp = rcu_dereference(nf_nat_snmp_hook);
if (nf_nat_snmp && ct->status & IPS_NAT_MASK)
--
2.11.0
^ permalink raw reply related
* [PATCH 05/30] netfilter: ipt_ah: return boolean instead of integer
From: Pablo Neira Ayuso @ 2018-03-12 17:58 UTC (permalink / raw)
To: netfilter-devel; +Cc: davem, netdev
In-Reply-To: <20180312175920.9022-1-pablo@netfilter.org>
From: "Gustavo A. R. Silva" <garsilva@embeddedor.com>
Return statements in functions returning bool should use
true/false instead of 1/0.
This issue was detected with the help of Coccinelle.
Signed-off-by: Gustavo A. R. Silva <garsilva@embeddedor.com>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
net/ipv4/netfilter/ipt_ah.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/net/ipv4/netfilter/ipt_ah.c b/net/ipv4/netfilter/ipt_ah.c
index a787d07f6cb7..7c6c20eaf4db 100644
--- a/net/ipv4/netfilter/ipt_ah.c
+++ b/net/ipv4/netfilter/ipt_ah.c
@@ -47,7 +47,7 @@ static bool ah_mt(const struct sk_buff *skb, struct xt_action_param *par)
*/
pr_debug("Dropping evil AH tinygram.\n");
par->hotdrop = true;
- return 0;
+ return false;
}
return spi_match(ahinfo->spis[0], ahinfo->spis[1],
--
2.11.0
^ permalink raw reply related
* [PATCH 06/30] netfilter: unlock xt_table earlier in __do_replace
From: Pablo Neira Ayuso @ 2018-03-12 17:58 UTC (permalink / raw)
To: netfilter-devel; +Cc: davem, netdev
In-Reply-To: <20180312175920.9022-1-pablo@netfilter.org>
From: Xin Long <lucien.xin@gmail.com>
Now it's doing cleanup_entry for oldinfo under the xt_table lock,
but it's not really necessary. After the replacement job is done
in xt_replace_table, oldinfo is not used elsewhere any more, and
it can be freed without xt_table lock safely.
The important thing is that rtnl_lock is called in some xt_target
destroy, which means rtnl_lock, a big lock is used in xt_table
lock, a smaller one. It usually could be the reason why a dead
lock may happen.
Besides, all xt_target/match checkentry is called out of xt_table
lock. It's better also to move all cleanup_entry calling out of
xt_table lock, just as do_replace_finish does for ebtables.
Signed-off-by: Xin Long <lucien.xin@gmail.com>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
net/ipv4/netfilter/arp_tables.c | 3 ++-
net/ipv4/netfilter/ip_tables.c | 3 ++-
net/ipv6/netfilter/ip6_tables.c | 3 ++-
3 files changed, 6 insertions(+), 3 deletions(-)
diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c
index c36ffce3c812..a0c7ce76879c 100644
--- a/net/ipv4/netfilter/arp_tables.c
+++ b/net/ipv4/netfilter/arp_tables.c
@@ -925,6 +925,8 @@ static int __do_replace(struct net *net, const char *name,
(newinfo->number <= oldinfo->initial_entries))
module_put(t->me);
+ xt_table_unlock(t);
+
get_old_counters(oldinfo, counters);
/* Decrease module usage counts and free resource */
@@ -939,7 +941,6 @@ static int __do_replace(struct net *net, const char *name,
net_warn_ratelimited("arptables: counters copy to user failed while replacing table\n");
}
vfree(counters);
- xt_table_unlock(t);
return ret;
put_module:
diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c
index d4f7584d2dbe..4f7153e25e0b 100644
--- a/net/ipv4/netfilter/ip_tables.c
+++ b/net/ipv4/netfilter/ip_tables.c
@@ -1087,6 +1087,8 @@ __do_replace(struct net *net, const char *name, unsigned int valid_hooks,
(newinfo->number <= oldinfo->initial_entries))
module_put(t->me);
+ xt_table_unlock(t);
+
get_old_counters(oldinfo, counters);
/* Decrease module usage counts and free resource */
@@ -1100,7 +1102,6 @@ __do_replace(struct net *net, const char *name, unsigned int valid_hooks,
net_warn_ratelimited("iptables: counters copy to user failed while replacing table\n");
}
vfree(counters);
- xt_table_unlock(t);
return ret;
put_module:
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c
index 4de8ac1e5af4..6c44033decab 100644
--- a/net/ipv6/netfilter/ip6_tables.c
+++ b/net/ipv6/netfilter/ip6_tables.c
@@ -1105,6 +1105,8 @@ __do_replace(struct net *net, const char *name, unsigned int valid_hooks,
(newinfo->number <= oldinfo->initial_entries))
module_put(t->me);
+ xt_table_unlock(t);
+
get_old_counters(oldinfo, counters);
/* Decrease module usage counts and free resource */
@@ -1118,7 +1120,6 @@ __do_replace(struct net *net, const char *name, unsigned int valid_hooks,
net_warn_ratelimited("ip6tables: counters copy to user failed while replacing table\n");
}
vfree(counters);
- xt_table_unlock(t);
return ret;
put_module:
--
2.11.0
^ permalink raw reply related
* [PATCH 07/30] netfilter: x_tables: check standard verdicts in core
From: Pablo Neira Ayuso @ 2018-03-12 17:58 UTC (permalink / raw)
To: netfilter-devel; +Cc: davem, netdev
In-Reply-To: <20180312175920.9022-1-pablo@netfilter.org>
From: Florian Westphal <fw@strlen.de>
Userspace must provide a valid verdict to the standard target.
The verdict can be either a jump (signed int > 0), or a return code.
Allowed return codes are either RETURN (pop from stack), NF_ACCEPT, DROP
and QUEUE (latter is allowed for legacy reasons).
Jump offsets (verdict > 0) are checked in more detail later on when
loop-detection is performed.
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
net/ipv4/netfilter/arp_tables.c | 5 -----
net/ipv4/netfilter/ip_tables.c | 5 -----
net/ipv6/netfilter/ip6_tables.c | 5 -----
net/netfilter/x_tables.c | 49 ++++++++++++++++++++++++++++++++++++-----
4 files changed, 43 insertions(+), 21 deletions(-)
diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c
index a0c7ce76879c..c9ffa884a4ee 100644
--- a/net/ipv4/netfilter/arp_tables.c
+++ b/net/ipv4/netfilter/arp_tables.c
@@ -334,11 +334,6 @@ static int mark_source_chains(const struct xt_table_info *newinfo,
t->verdict < 0) || visited) {
unsigned int oldpos, size;
- if ((strcmp(t->target.u.user.name,
- XT_STANDARD_TARGET) == 0) &&
- t->verdict < -NF_MAX_VERDICT - 1)
- return 0;
-
/* Return: backtrack through the last
* big jump.
*/
diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c
index 4f7153e25e0b..c9b57a6bf96a 100644
--- a/net/ipv4/netfilter/ip_tables.c
+++ b/net/ipv4/netfilter/ip_tables.c
@@ -402,11 +402,6 @@ mark_source_chains(const struct xt_table_info *newinfo,
t->verdict < 0) || visited) {
unsigned int oldpos, size;
- if ((strcmp(t->target.u.user.name,
- XT_STANDARD_TARGET) == 0) &&
- t->verdict < -NF_MAX_VERDICT - 1)
- return 0;
-
/* Return: backtrack through the last
big jump. */
do {
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c
index 6c44033decab..f46954221933 100644
--- a/net/ipv6/netfilter/ip6_tables.c
+++ b/net/ipv6/netfilter/ip6_tables.c
@@ -420,11 +420,6 @@ mark_source_chains(const struct xt_table_info *newinfo,
t->verdict < 0) || visited) {
unsigned int oldpos, size;
- if ((strcmp(t->target.u.user.name,
- XT_STANDARD_TARGET) == 0) &&
- t->verdict < -NF_MAX_VERDICT - 1)
- return 0;
-
/* Return: backtrack through the last
big jump. */
do {
diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c
index d9deebe599ec..2e4d423e58e6 100644
--- a/net/netfilter/x_tables.c
+++ b/net/netfilter/x_tables.c
@@ -654,6 +654,31 @@ struct compat_xt_standard_target {
compat_uint_t verdict;
};
+static bool verdict_ok(int verdict)
+{
+ if (verdict > 0)
+ return true;
+
+ if (verdict < 0) {
+ int v = -verdict - 1;
+
+ if (verdict == XT_RETURN)
+ return true;
+
+ switch (v) {
+ case NF_ACCEPT: return true;
+ case NF_DROP: return true;
+ case NF_QUEUE: return true;
+ default:
+ break;
+ }
+
+ return false;
+ }
+
+ return false;
+}
+
int xt_compat_check_entry_offsets(const void *base, const char *elems,
unsigned int target_offset,
unsigned int next_offset)
@@ -675,9 +700,15 @@ int xt_compat_check_entry_offsets(const void *base, const char *elems,
if (target_offset + t->u.target_size > next_offset)
return -EINVAL;
- if (strcmp(t->u.user.name, XT_STANDARD_TARGET) == 0 &&
- COMPAT_XT_ALIGN(target_offset + sizeof(struct compat_xt_standard_target)) != next_offset)
- return -EINVAL;
+ if (strcmp(t->u.user.name, XT_STANDARD_TARGET) == 0) {
+ const struct compat_xt_standard_target *st = (const void *)t;
+
+ if (COMPAT_XT_ALIGN(target_offset + sizeof(*st)) != next_offset)
+ return -EINVAL;
+
+ if (!verdict_ok(st->verdict))
+ return -EINVAL;
+ }
/* compat_xt_entry match has less strict alignment requirements,
* otherwise they are identical. In case of padding differences
@@ -757,9 +788,15 @@ int xt_check_entry_offsets(const void *base,
if (target_offset + t->u.target_size > next_offset)
return -EINVAL;
- if (strcmp(t->u.user.name, XT_STANDARD_TARGET) == 0 &&
- XT_ALIGN(target_offset + sizeof(struct xt_standard_target)) != next_offset)
- return -EINVAL;
+ if (strcmp(t->u.user.name, XT_STANDARD_TARGET) == 0) {
+ const struct xt_standard_target *st = (const void *)t;
+
+ if (XT_ALIGN(target_offset + sizeof(*st)) != next_offset)
+ return -EINVAL;
+
+ if (!verdict_ok(st->verdict))
+ return -EINVAL;
+ }
return xt_check_entry_match(elems, base + target_offset,
__alignof__(struct xt_entry_match));
--
2.11.0
^ permalink raw reply related
* [PATCH 08/30] netfilter: x_tables: check error target size too
From: Pablo Neira Ayuso @ 2018-03-12 17:58 UTC (permalink / raw)
To: netfilter-devel; +Cc: davem, netdev
In-Reply-To: <20180312175920.9022-1-pablo@netfilter.org>
From: Florian Westphal <fw@strlen.de>
Check that userspace ERROR target (custom user-defined chains) match
expected format, and the chain name is null terminated.
This is irrelevant for kernel, but iptables itself relies on sane input
when it dumps rules from kernel.
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
net/netfilter/x_tables.c | 23 +++++++++++++++++++++++
1 file changed, 23 insertions(+)
diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c
index 2e4d423e58e6..f045bb4f7063 100644
--- a/net/netfilter/x_tables.c
+++ b/net/netfilter/x_tables.c
@@ -654,6 +654,11 @@ struct compat_xt_standard_target {
compat_uint_t verdict;
};
+struct compat_xt_error_target {
+ struct compat_xt_entry_target t;
+ char errorname[XT_FUNCTION_MAXNAMELEN];
+};
+
static bool verdict_ok(int verdict)
{
if (verdict > 0)
@@ -679,6 +684,12 @@ static bool verdict_ok(int verdict)
return false;
}
+static bool error_tg_ok(unsigned int usersize, unsigned int kernsize,
+ const char *msg, unsigned int msglen)
+{
+ return usersize == kernsize && strnlen(msg, msglen) < msglen;
+}
+
int xt_compat_check_entry_offsets(const void *base, const char *elems,
unsigned int target_offset,
unsigned int next_offset)
@@ -708,6 +719,12 @@ int xt_compat_check_entry_offsets(const void *base, const char *elems,
if (!verdict_ok(st->verdict))
return -EINVAL;
+ } else if (strcmp(t->u.user.name, XT_ERROR_TARGET) == 0) {
+ const struct compat_xt_error_target *et = (const void *)t;
+
+ if (!error_tg_ok(t->u.target_size, sizeof(*et),
+ et->errorname, sizeof(et->errorname)))
+ return -EINVAL;
}
/* compat_xt_entry match has less strict alignment requirements,
@@ -796,6 +813,12 @@ int xt_check_entry_offsets(const void *base,
if (!verdict_ok(st->verdict))
return -EINVAL;
+ } else if (strcmp(t->u.user.name, XT_ERROR_TARGET) == 0) {
+ const struct xt_error_target *et = (const void *)t;
+
+ if (!error_tg_ok(t->u.target_size, sizeof(*et),
+ et->errorname, sizeof(et->errorname)))
+ return -EINVAL;
}
return xt_check_entry_match(elems, base + target_offset,
--
2.11.0
^ permalink raw reply related
* [PATCH 09/30] netfilter: x_tables: move hook entry checks into core
From: Pablo Neira Ayuso @ 2018-03-12 17:58 UTC (permalink / raw)
To: netfilter-devel; +Cc: davem, netdev
In-Reply-To: <20180312175920.9022-1-pablo@netfilter.org>
From: Florian Westphal <fw@strlen.de>
Allow followup patch to change on location instead of three.
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
include/linux/netfilter/x_tables.h | 2 ++
net/ipv4/netfilter/arp_tables.c | 13 +++----------
net/ipv4/netfilter/ip_tables.c | 13 +++----------
net/ipv6/netfilter/ip6_tables.c | 13 +++----------
net/netfilter/x_tables.c | 29 +++++++++++++++++++++++++++++
5 files changed, 40 insertions(+), 30 deletions(-)
diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h
index 1313b35c3ab7..fa0c19c328f1 100644
--- a/include/linux/netfilter/x_tables.h
+++ b/include/linux/netfilter/x_tables.h
@@ -281,6 +281,8 @@ int xt_check_entry_offsets(const void *base, const char *elems,
unsigned int target_offset,
unsigned int next_offset);
+int xt_check_table_hooks(const struct xt_table_info *info, unsigned int valid_hooks);
+
unsigned int *xt_alloc_entry_offsets(unsigned int size);
bool xt_find_jump_offset(const unsigned int *offsets,
unsigned int target, unsigned int size);
diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c
index c9ffa884a4ee..be5821215ea0 100644
--- a/net/ipv4/netfilter/arp_tables.c
+++ b/net/ipv4/netfilter/arp_tables.c
@@ -555,16 +555,9 @@ static int translate_table(struct xt_table_info *newinfo, void *entry0,
if (i != repl->num_entries)
goto out_free;
- /* Check hooks all assigned */
- for (i = 0; i < NF_ARP_NUMHOOKS; i++) {
- /* Only hooks which are valid */
- if (!(repl->valid_hooks & (1 << i)))
- continue;
- if (newinfo->hook_entry[i] == 0xFFFFFFFF)
- goto out_free;
- if (newinfo->underflow[i] == 0xFFFFFFFF)
- goto out_free;
- }
+ ret = xt_check_table_hooks(newinfo, repl->valid_hooks);
+ if (ret)
+ goto out_free;
if (!mark_source_chains(newinfo, repl->valid_hooks, entry0, offsets)) {
ret = -ELOOP;
diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c
index c9b57a6bf96a..29bda9484a33 100644
--- a/net/ipv4/netfilter/ip_tables.c
+++ b/net/ipv4/netfilter/ip_tables.c
@@ -702,16 +702,9 @@ translate_table(struct net *net, struct xt_table_info *newinfo, void *entry0,
if (i != repl->num_entries)
goto out_free;
- /* Check hooks all assigned */
- for (i = 0; i < NF_INET_NUMHOOKS; i++) {
- /* Only hooks which are valid */
- if (!(repl->valid_hooks & (1 << i)))
- continue;
- if (newinfo->hook_entry[i] == 0xFFFFFFFF)
- goto out_free;
- if (newinfo->underflow[i] == 0xFFFFFFFF)
- goto out_free;
- }
+ ret = xt_check_table_hooks(newinfo, repl->valid_hooks);
+ if (ret)
+ goto out_free;
if (!mark_source_chains(newinfo, repl->valid_hooks, entry0, offsets)) {
ret = -ELOOP;
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c
index f46954221933..ba3776a4d305 100644
--- a/net/ipv6/netfilter/ip6_tables.c
+++ b/net/ipv6/netfilter/ip6_tables.c
@@ -720,16 +720,9 @@ translate_table(struct net *net, struct xt_table_info *newinfo, void *entry0,
if (i != repl->num_entries)
goto out_free;
- /* Check hooks all assigned */
- for (i = 0; i < NF_INET_NUMHOOKS; i++) {
- /* Only hooks which are valid */
- if (!(repl->valid_hooks & (1 << i)))
- continue;
- if (newinfo->hook_entry[i] == 0xFFFFFFFF)
- goto out_free;
- if (newinfo->underflow[i] == 0xFFFFFFFF)
- goto out_free;
- }
+ ret = xt_check_table_hooks(newinfo, repl->valid_hooks);
+ if (ret)
+ goto out_free;
if (!mark_source_chains(newinfo, repl->valid_hooks, entry0, offsets)) {
ret = -ELOOP;
diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c
index f045bb4f7063..5d8ba89a8da8 100644
--- a/net/netfilter/x_tables.c
+++ b/net/netfilter/x_tables.c
@@ -518,6 +518,35 @@ static int xt_check_entry_match(const char *match, const char *target,
return 0;
}
+/** xt_check_table_hooks - check hook entry points are sane
+ *
+ * @info xt_table_info to check
+ * @valid_hooks - hook entry points that we can enter from
+ *
+ * Validates that the hook entry and underflows points are set up.
+ *
+ * Return: 0 on success, negative errno on failure.
+ */
+int xt_check_table_hooks(const struct xt_table_info *info, unsigned int valid_hooks)
+{
+ unsigned int i;
+
+ BUILD_BUG_ON(ARRAY_SIZE(info->hook_entry) != ARRAY_SIZE(info->underflow));
+
+ for (i = 0; i < ARRAY_SIZE(info->hook_entry); i++) {
+ if (!(valid_hooks & (1 << i)))
+ continue;
+
+ if (info->hook_entry[i] == 0xFFFFFFFF)
+ return -EINVAL;
+ if (info->underflow[i] == 0xFFFFFFFF)
+ return -EINVAL;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(xt_check_table_hooks);
+
#ifdef CONFIG_COMPAT
int xt_compat_add_offset(u_int8_t af, unsigned int offset, int delta)
{
--
2.11.0
^ permalink raw reply related
* [PATCH 10/30] netfilter: x_tables: enforce unique and ascending entry points
From: Pablo Neira Ayuso @ 2018-03-12 17:59 UTC (permalink / raw)
To: netfilter-devel; +Cc: davem, netdev
In-Reply-To: <20180312175920.9022-1-pablo@netfilter.org>
From: Florian Westphal <fw@strlen.de>
Harmless from kernel point of view, but iptables assumes that this is
true when decoding a ruleset.
iptables walks the dumped blob from kernel, and, for each entry that
creates a new chain it prints out rule/chain information.
Base chains (hook entry points) are thus only shown when they appear
in the rule blob. One base chain that is referenced multiple times
in hook blob is then only printed once.
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
net/netfilter/x_tables.c | 31 ++++++++++++++++++++++++++++++-
1 file changed, 30 insertions(+), 1 deletion(-)
diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c
index 5d8ba89a8da8..4e6cbb38e616 100644
--- a/net/netfilter/x_tables.c
+++ b/net/netfilter/x_tables.c
@@ -529,10 +529,15 @@ static int xt_check_entry_match(const char *match, const char *target,
*/
int xt_check_table_hooks(const struct xt_table_info *info, unsigned int valid_hooks)
{
- unsigned int i;
+ const char *err = "unsorted underflow";
+ unsigned int i, max_uflow, max_entry;
+ bool check_hooks = false;
BUILD_BUG_ON(ARRAY_SIZE(info->hook_entry) != ARRAY_SIZE(info->underflow));
+ max_entry = 0;
+ max_uflow = 0;
+
for (i = 0; i < ARRAY_SIZE(info->hook_entry); i++) {
if (!(valid_hooks & (1 << i)))
continue;
@@ -541,9 +546,33 @@ int xt_check_table_hooks(const struct xt_table_info *info, unsigned int valid_ho
return -EINVAL;
if (info->underflow[i] == 0xFFFFFFFF)
return -EINVAL;
+
+ if (check_hooks) {
+ if (max_uflow > info->underflow[i])
+ goto error;
+
+ if (max_uflow == info->underflow[i]) {
+ err = "duplicate underflow";
+ goto error;
+ }
+ if (max_entry > info->hook_entry[i]) {
+ err = "unsorted entry";
+ goto error;
+ }
+ if (max_entry == info->hook_entry[i]) {
+ err = "duplicate entry";
+ goto error;
+ }
+ }
+ max_entry = info->hook_entry[i];
+ max_uflow = info->underflow[i];
+ check_hooks = true;
}
return 0;
+error:
+ pr_err_ratelimited("%s at hook %d\n", err, i);
+ return -EINVAL;
}
EXPORT_SYMBOL(xt_check_table_hooks);
--
2.11.0
^ permalink raw reply related
* [PATCH 11/30] netfilter: x_tables: cap allocations at 512 mbyte
From: Pablo Neira Ayuso @ 2018-03-12 17:59 UTC (permalink / raw)
To: netfilter-devel; +Cc: davem, netdev
In-Reply-To: <20180312175920.9022-1-pablo@netfilter.org>
From: Florian Westphal <fw@strlen.de>
Arbitrary limit, however, this still allows huge rulesets
(> 1 million rules). This helps with automated fuzzer as it prevents
oom-killer invocation.
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
net/netfilter/x_tables.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c
index 4e6cbb38e616..dc68ac49614a 100644
--- a/net/netfilter/x_tables.c
+++ b/net/netfilter/x_tables.c
@@ -40,6 +40,7 @@ MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
MODULE_DESCRIPTION("{ip,ip6,arp,eb}_tables backend module");
#define XT_PCPU_BLOCK_SIZE 4096
+#define XT_MAX_TABLE_SIZE (512 * 1024 * 1024)
struct compat_delta {
unsigned int offset; /* offset in kernel */
@@ -1117,7 +1118,7 @@ struct xt_table_info *xt_alloc_table_info(unsigned int size)
struct xt_table_info *info = NULL;
size_t sz = sizeof(*info) + size;
- if (sz < sizeof(*info))
+ if (sz < sizeof(*info) || sz >= XT_MAX_TABLE_SIZE)
return NULL;
/* __GFP_NORETRY is not fully supported by kvmalloc but it should
--
2.11.0
^ permalink raw reply related
* [PATCH 12/30] netfilter: x_tables: limit allocation requests for blob rule heads
From: Pablo Neira Ayuso @ 2018-03-12 17:59 UTC (permalink / raw)
To: netfilter-devel; +Cc: davem, netdev
In-Reply-To: <20180312175920.9022-1-pablo@netfilter.org>
From: Florian Westphal <fw@strlen.de>
This is a very conservative limit (134217728 rules), but good
enough to not trigger frequent oom from syzkaller.
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
net/netfilter/x_tables.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c
index dc68ac49614a..01f8e122e74e 100644
--- a/net/netfilter/x_tables.c
+++ b/net/netfilter/x_tables.c
@@ -894,6 +894,9 @@ EXPORT_SYMBOL(xt_check_entry_offsets);
*/
unsigned int *xt_alloc_entry_offsets(unsigned int size)
{
+ if (size > XT_MAX_TABLE_SIZE / sizeof(unsigned int))
+ return NULL;
+
return kvmalloc_array(size, sizeof(unsigned int), GFP_KERNEL | __GFP_ZERO);
}
--
2.11.0
^ permalink raw reply related
* [PATCH 13/30] netfilter: x_tables: add counters allocation wrapper
From: Pablo Neira Ayuso @ 2018-03-12 17:59 UTC (permalink / raw)
To: netfilter-devel; +Cc: davem, netdev
In-Reply-To: <20180312175920.9022-1-pablo@netfilter.org>
From: Florian Westphal <fw@strlen.de>
allows to have size checks in a single spot.
This is supposed to reduce oom situations when fuzz-testing xtables.
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
include/linux/netfilter/x_tables.h | 1 +
net/ipv4/netfilter/arp_tables.c | 2 +-
net/ipv4/netfilter/ip_tables.c | 2 +-
net/ipv6/netfilter/ip6_tables.c | 2 +-
net/netfilter/x_tables.c | 15 +++++++++++++++
5 files changed, 19 insertions(+), 3 deletions(-)
diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h
index fa0c19c328f1..0bd93c589a8c 100644
--- a/include/linux/netfilter/x_tables.h
+++ b/include/linux/netfilter/x_tables.h
@@ -301,6 +301,7 @@ int xt_data_to_user(void __user *dst, const void *src,
void *xt_copy_counters_from_user(const void __user *user, unsigned int len,
struct xt_counters_info *info, bool compat);
+struct xt_counters *xt_counters_alloc(unsigned int counters);
struct xt_table *xt_register_table(struct net *net,
const struct xt_table *table,
diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c
index be5821215ea0..82ba09b50fdb 100644
--- a/net/ipv4/netfilter/arp_tables.c
+++ b/net/ipv4/netfilter/arp_tables.c
@@ -883,7 +883,7 @@ static int __do_replace(struct net *net, const char *name,
struct arpt_entry *iter;
ret = 0;
- counters = vzalloc(num_counters * sizeof(struct xt_counters));
+ counters = xt_counters_alloc(num_counters);
if (!counters) {
ret = -ENOMEM;
goto out;
diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c
index 29bda9484a33..4901ca6c3e09 100644
--- a/net/ipv4/netfilter/ip_tables.c
+++ b/net/ipv4/netfilter/ip_tables.c
@@ -1045,7 +1045,7 @@ __do_replace(struct net *net, const char *name, unsigned int valid_hooks,
struct ipt_entry *iter;
ret = 0;
- counters = vzalloc(num_counters * sizeof(struct xt_counters));
+ counters = xt_counters_alloc(num_counters);
if (!counters) {
ret = -ENOMEM;
goto out;
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c
index ba3776a4d305..e84cec49b60f 100644
--- a/net/ipv6/netfilter/ip6_tables.c
+++ b/net/ipv6/netfilter/ip6_tables.c
@@ -1063,7 +1063,7 @@ __do_replace(struct net *net, const char *name, unsigned int valid_hooks,
struct ip6t_entry *iter;
ret = 0;
- counters = vzalloc(num_counters * sizeof(struct xt_counters));
+ counters = xt_counters_alloc(num_counters);
if (!counters) {
ret = -ENOMEM;
goto out;
diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c
index 01f8e122e74e..82b1f8f52ac6 100644
--- a/net/netfilter/x_tables.c
+++ b/net/netfilter/x_tables.c
@@ -1290,6 +1290,21 @@ static int xt_jumpstack_alloc(struct xt_table_info *i)
return 0;
}
+struct xt_counters *xt_counters_alloc(unsigned int counters)
+{
+ struct xt_counters *mem;
+
+ if (counters == 0 || counters > INT_MAX / sizeof(*mem))
+ return NULL;
+
+ counters *= sizeof(*mem);
+ if (counters > XT_MAX_TABLE_SIZE)
+ return NULL;
+
+ return vzalloc(counters);
+}
+EXPORT_SYMBOL(xt_counters_alloc);
+
struct xt_table_info *
xt_replace_table(struct xt_table *table,
unsigned int num_counters,
--
2.11.0
^ permalink raw reply related
* [PATCH 14/30] netfilter: compat: prepare xt_compat_init_offsets to return errors
From: Pablo Neira Ayuso @ 2018-03-12 17:59 UTC (permalink / raw)
To: netfilter-devel; +Cc: davem, netdev
In-Reply-To: <20180312175920.9022-1-pablo@netfilter.org>
From: Florian Westphal <fw@strlen.de>
should have no impact, function still always returns 0.
This patch is only to ease review.
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
include/linux/netfilter/x_tables.h | 2 +-
net/bridge/netfilter/ebtables.c | 10 ++++++++--
net/ipv4/netfilter/arp_tables.c | 10 +++++++---
net/ipv4/netfilter/ip_tables.c | 8 ++++++--
net/ipv6/netfilter/ip6_tables.c | 10 +++++++---
net/netfilter/x_tables.c | 4 +++-
6 files changed, 32 insertions(+), 12 deletions(-)
diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h
index 0bd93c589a8c..7bd896dc78df 100644
--- a/include/linux/netfilter/x_tables.h
+++ b/include/linux/netfilter/x_tables.h
@@ -510,7 +510,7 @@ void xt_compat_unlock(u_int8_t af);
int xt_compat_add_offset(u_int8_t af, unsigned int offset, int delta);
void xt_compat_flush_offsets(u_int8_t af);
-void xt_compat_init_offsets(u_int8_t af, unsigned int number);
+int xt_compat_init_offsets(u8 af, unsigned int number);
int xt_compat_calc_jump(u_int8_t af, unsigned int offset);
int xt_compat_match_offset(const struct xt_match *match);
diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c
index 02c4b409d317..217aa79f7b2a 100644
--- a/net/bridge/netfilter/ebtables.c
+++ b/net/bridge/netfilter/ebtables.c
@@ -1819,10 +1819,14 @@ static int compat_table_info(const struct ebt_table_info *info,
{
unsigned int size = info->entries_size;
const void *entries = info->entries;
+ int ret;
newinfo->entries_size = size;
- xt_compat_init_offsets(NFPROTO_BRIDGE, info->nentries);
+ ret = xt_compat_init_offsets(NFPROTO_BRIDGE, info->nentries);
+ if (ret)
+ return ret;
+
return EBT_ENTRY_ITERATE(entries, size, compat_calc_entry, info,
entries, newinfo);
}
@@ -2245,7 +2249,9 @@ static int compat_do_replace(struct net *net, void __user *user,
xt_compat_lock(NFPROTO_BRIDGE);
- xt_compat_init_offsets(NFPROTO_BRIDGE, tmp.nentries);
+ ret = xt_compat_init_offsets(NFPROTO_BRIDGE, tmp.nentries);
+ if (ret < 0)
+ goto out_unlock;
ret = compat_copy_entries(entries_tmp, tmp.entries_size, &state);
if (ret < 0)
goto out_unlock;
diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c
index 82ba09b50fdb..aaafdbd15ad3 100644
--- a/net/ipv4/netfilter/arp_tables.c
+++ b/net/ipv4/netfilter/arp_tables.c
@@ -769,7 +769,9 @@ static int compat_table_info(const struct xt_table_info *info,
memcpy(newinfo, info, offsetof(struct xt_table_info, entries));
newinfo->initial_entries = 0;
loc_cpu_entry = info->entries;
- xt_compat_init_offsets(NFPROTO_ARP, info->number);
+ ret = xt_compat_init_offsets(NFPROTO_ARP, info->number);
+ if (ret)
+ return ret;
xt_entry_foreach(iter, loc_cpu_entry, info->size) {
ret = compat_calc_entry(iter, info, loc_cpu_entry, newinfo);
if (ret != 0)
@@ -1156,7 +1158,7 @@ static int translate_compat_table(struct xt_table_info **pinfo,
struct compat_arpt_entry *iter0;
struct arpt_replace repl;
unsigned int size;
- int ret = 0;
+ int ret;
info = *pinfo;
entry0 = *pentry0;
@@ -1165,7 +1167,9 @@ static int translate_compat_table(struct xt_table_info **pinfo,
j = 0;
xt_compat_lock(NFPROTO_ARP);
- xt_compat_init_offsets(NFPROTO_ARP, compatr->num_entries);
+ ret = xt_compat_init_offsets(NFPROTO_ARP, compatr->num_entries);
+ if (ret)
+ goto out_unlock;
/* Walk through entries, checking offsets. */
xt_entry_foreach(iter0, entry0, compatr->size) {
ret = check_compat_entry_size_and_hooks(iter0, info, &size,
diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c
index 4901ca6c3e09..f9063513f9d1 100644
--- a/net/ipv4/netfilter/ip_tables.c
+++ b/net/ipv4/netfilter/ip_tables.c
@@ -933,7 +933,9 @@ static int compat_table_info(const struct xt_table_info *info,
memcpy(newinfo, info, offsetof(struct xt_table_info, entries));
newinfo->initial_entries = 0;
loc_cpu_entry = info->entries;
- xt_compat_init_offsets(AF_INET, info->number);
+ ret = xt_compat_init_offsets(AF_INET, info->number);
+ if (ret)
+ return ret;
xt_entry_foreach(iter, loc_cpu_entry, info->size) {
ret = compat_calc_entry(iter, info, loc_cpu_entry, newinfo);
if (ret != 0)
@@ -1407,7 +1409,9 @@ translate_compat_table(struct net *net,
j = 0;
xt_compat_lock(AF_INET);
- xt_compat_init_offsets(AF_INET, compatr->num_entries);
+ ret = xt_compat_init_offsets(AF_INET, compatr->num_entries);
+ if (ret)
+ goto out_unlock;
/* Walk through entries, checking offsets. */
xt_entry_foreach(iter0, entry0, compatr->size) {
ret = check_compat_entry_size_and_hooks(iter0, info, &size,
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c
index e84cec49b60f..3c36a4c77f29 100644
--- a/net/ipv6/netfilter/ip6_tables.c
+++ b/net/ipv6/netfilter/ip6_tables.c
@@ -950,7 +950,9 @@ static int compat_table_info(const struct xt_table_info *info,
memcpy(newinfo, info, offsetof(struct xt_table_info, entries));
newinfo->initial_entries = 0;
loc_cpu_entry = info->entries;
- xt_compat_init_offsets(AF_INET6, info->number);
+ ret = xt_compat_init_offsets(AF_INET6, info->number);
+ if (ret)
+ return ret;
xt_entry_foreach(iter, loc_cpu_entry, info->size) {
ret = compat_calc_entry(iter, info, loc_cpu_entry, newinfo);
if (ret != 0)
@@ -1414,7 +1416,7 @@ translate_compat_table(struct net *net,
struct compat_ip6t_entry *iter0;
struct ip6t_replace repl;
unsigned int size;
- int ret = 0;
+ int ret;
info = *pinfo;
entry0 = *pentry0;
@@ -1423,7 +1425,9 @@ translate_compat_table(struct net *net,
j = 0;
xt_compat_lock(AF_INET6);
- xt_compat_init_offsets(AF_INET6, compatr->num_entries);
+ ret = xt_compat_init_offsets(AF_INET6, compatr->num_entries);
+ if (ret)
+ goto out_unlock;
/* Walk through entries, checking offsets. */
xt_entry_foreach(iter0, entry0, compatr->size) {
ret = check_compat_entry_size_and_hooks(iter0, info, &size,
diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c
index 82b1f8f52ac6..e878c85a9268 100644
--- a/net/netfilter/x_tables.c
+++ b/net/netfilter/x_tables.c
@@ -632,10 +632,12 @@ int xt_compat_calc_jump(u_int8_t af, unsigned int offset)
}
EXPORT_SYMBOL_GPL(xt_compat_calc_jump);
-void xt_compat_init_offsets(u_int8_t af, unsigned int number)
+int xt_compat_init_offsets(u8 af, unsigned int number)
{
xt[af].number = number;
xt[af].cur = 0;
+
+ return 0;
}
EXPORT_SYMBOL(xt_compat_init_offsets);
--
2.11.0
^ permalink raw reply related
* [PATCH 15/30] netfilter: compat: reject huge allocation requests
From: Pablo Neira Ayuso @ 2018-03-12 17:59 UTC (permalink / raw)
To: netfilter-devel; +Cc: davem, netdev
In-Reply-To: <20180312175920.9022-1-pablo@netfilter.org>
From: Florian Westphal <fw@strlen.de>
no need to bother even trying to allocating huge compat offset arrays,
such ruleset is rejected later on anyway becaus we refuse to allocate
overly large rule blobs.
However, compat translation happens before blob allocation, so we should
add a check there too.
This is supposed to help with fuzzing by avoiding oom-killer.
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
net/netfilter/x_tables.c | 26 ++++++++++++++++++--------
1 file changed, 18 insertions(+), 8 deletions(-)
diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c
index e878c85a9268..33724b08b8f0 100644
--- a/net/netfilter/x_tables.c
+++ b/net/netfilter/x_tables.c
@@ -582,14 +582,8 @@ int xt_compat_add_offset(u_int8_t af, unsigned int offset, int delta)
{
struct xt_af *xp = &xt[af];
- if (!xp->compat_tab) {
- if (!xp->number)
- return -EINVAL;
- xp->compat_tab = vmalloc(sizeof(struct compat_delta) * xp->number);
- if (!xp->compat_tab)
- return -ENOMEM;
- xp->cur = 0;
- }
+ if (WARN_ON(!xp->compat_tab))
+ return -ENOMEM;
if (xp->cur >= xp->number)
return -EINVAL;
@@ -634,6 +628,22 @@ EXPORT_SYMBOL_GPL(xt_compat_calc_jump);
int xt_compat_init_offsets(u8 af, unsigned int number)
{
+ size_t mem;
+
+ if (!number || number > (INT_MAX / sizeof(struct compat_delta)))
+ return -EINVAL;
+
+ if (WARN_ON(xt[af].compat_tab))
+ return -EINVAL;
+
+ mem = sizeof(struct compat_delta) * number;
+ if (mem > XT_MAX_TABLE_SIZE)
+ return -ENOMEM;
+
+ xt[af].compat_tab = vmalloc(mem);
+ if (!xt[af].compat_tab)
+ return -ENOMEM;
+
xt[af].number = number;
xt[af].cur = 0;
--
2.11.0
^ permalink raw reply related
* [PATCH 16/30] netfilter: x_tables: make sure compat af mutex is held
From: Pablo Neira Ayuso @ 2018-03-12 17:59 UTC (permalink / raw)
To: netfilter-devel; +Cc: davem, netdev
In-Reply-To: <20180312175920.9022-1-pablo@netfilter.org>
From: Florian Westphal <fw@strlen.de>
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
net/netfilter/x_tables.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c
index 33724b08b8f0..7521e8a72c06 100644
--- a/net/netfilter/x_tables.c
+++ b/net/netfilter/x_tables.c
@@ -582,6 +582,8 @@ int xt_compat_add_offset(u_int8_t af, unsigned int offset, int delta)
{
struct xt_af *xp = &xt[af];
+ WARN_ON(!mutex_is_locked(&xt[af].compat_mutex));
+
if (WARN_ON(!xp->compat_tab))
return -ENOMEM;
@@ -599,6 +601,8 @@ EXPORT_SYMBOL_GPL(xt_compat_add_offset);
void xt_compat_flush_offsets(u_int8_t af)
{
+ WARN_ON(!mutex_is_locked(&xt[af].compat_mutex));
+
if (xt[af].compat_tab) {
vfree(xt[af].compat_tab);
xt[af].compat_tab = NULL;
@@ -630,6 +634,8 @@ int xt_compat_init_offsets(u8 af, unsigned int number)
{
size_t mem;
+ WARN_ON(!mutex_is_locked(&xt[af].compat_mutex));
+
if (!number || number > (INT_MAX / sizeof(struct compat_delta)))
return -EINVAL;
--
2.11.0
^ permalink raw reply related
* [PATCH 17/30] netfilter: x_tables: ensure last rule in base chain matches underflow/policy
From: Pablo Neira Ayuso @ 2018-03-12 17:59 UTC (permalink / raw)
To: netfilter-devel; +Cc: davem, netdev
In-Reply-To: <20180312175920.9022-1-pablo@netfilter.org>
From: Florian Westphal <fw@strlen.de>
Harmless from kernel point of view, but again iptables assumes that
this is true when decoding ruleset coming from kernel.
If a (syzkaller generated) ruleset doesn't have the underflow/policy
stored as the last rule in the base chain, then iptables will abort()
because it doesn't find the chain policy.
libiptc assumes that the policy is the last rule in the basechain, which
is only true for iptables-generated rulesets.
Unfortunately this needs code duplication -- the functions need the
struct layout of the rule head, but that is different for
ip/ip6/arptables.
NB: pr_warn could be pr_debug but in case this break rulesets somehow its
useful to know why blob was rejected.
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
net/ipv4/netfilter/arp_tables.c | 17 ++++++++++++++++-
net/ipv4/netfilter/ip_tables.c | 17 ++++++++++++++++-
net/ipv6/netfilter/ip6_tables.c | 17 ++++++++++++++++-
3 files changed, 48 insertions(+), 3 deletions(-)
diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c
index aaafdbd15ad3..f366ff1cfc19 100644
--- a/net/ipv4/netfilter/arp_tables.c
+++ b/net/ipv4/netfilter/arp_tables.c
@@ -309,10 +309,13 @@ static int mark_source_chains(const struct xt_table_info *newinfo,
for (hook = 0; hook < NF_ARP_NUMHOOKS; hook++) {
unsigned int pos = newinfo->hook_entry[hook];
struct arpt_entry *e = entry0 + pos;
+ unsigned int last_pos, depth;
if (!(valid_hooks & (1 << hook)))
continue;
+ depth = 0;
+ last_pos = pos;
/* Set initial back pointer. */
e->counters.pcnt = pos;
@@ -343,6 +346,8 @@ static int mark_source_chains(const struct xt_table_info *newinfo,
pos = e->counters.pcnt;
e->counters.pcnt = 0;
+ if (depth)
+ --depth;
/* We're at the start. */
if (pos == oldpos)
goto next;
@@ -367,6 +372,9 @@ static int mark_source_chains(const struct xt_table_info *newinfo,
if (!xt_find_jump_offset(offsets, newpos,
newinfo->number))
return 0;
+
+ if (entry0 + newpos != arpt_next_entry(e))
+ ++depth;
} else {
/* ... this is a fallthru */
newpos = pos + e->next_offset;
@@ -377,8 +385,15 @@ static int mark_source_chains(const struct xt_table_info *newinfo,
e->counters.pcnt = pos;
pos = newpos;
}
+ if (depth == 0)
+ last_pos = pos;
+ }
+next:
+ if (last_pos != newinfo->underflow[hook]) {
+ pr_err_ratelimited("last base chain position %u doesn't match underflow %u (hook %u)\n",
+ last_pos, newinfo->underflow[hook], hook);
+ return 0;
}
-next: ;
}
return 1;
}
diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c
index f9063513f9d1..2362ca2c9e0c 100644
--- a/net/ipv4/netfilter/ip_tables.c
+++ b/net/ipv4/netfilter/ip_tables.c
@@ -378,10 +378,13 @@ mark_source_chains(const struct xt_table_info *newinfo,
for (hook = 0; hook < NF_INET_NUMHOOKS; hook++) {
unsigned int pos = newinfo->hook_entry[hook];
struct ipt_entry *e = entry0 + pos;
+ unsigned int last_pos, depth;
if (!(valid_hooks & (1 << hook)))
continue;
+ depth = 0;
+ last_pos = pos;
/* Set initial back pointer. */
e->counters.pcnt = pos;
@@ -410,6 +413,8 @@ mark_source_chains(const struct xt_table_info *newinfo,
pos = e->counters.pcnt;
e->counters.pcnt = 0;
+ if (depth)
+ --depth;
/* We're at the start. */
if (pos == oldpos)
goto next;
@@ -434,6 +439,9 @@ mark_source_chains(const struct xt_table_info *newinfo,
if (!xt_find_jump_offset(offsets, newpos,
newinfo->number))
return 0;
+
+ if (entry0 + newpos != ipt_next_entry(e))
+ ++depth;
} else {
/* ... this is a fallthru */
newpos = pos + e->next_offset;
@@ -444,8 +452,15 @@ mark_source_chains(const struct xt_table_info *newinfo,
e->counters.pcnt = pos;
pos = newpos;
}
+ if (depth == 0)
+ last_pos = pos;
+ }
+next:
+ if (last_pos != newinfo->underflow[hook]) {
+ pr_err_ratelimited("last base chain position %u doesn't match underflow %u (hook %u)\n",
+ last_pos, newinfo->underflow[hook], hook);
+ return 0;
}
-next: ;
}
return 1;
}
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c
index 3c36a4c77f29..004508753abc 100644
--- a/net/ipv6/netfilter/ip6_tables.c
+++ b/net/ipv6/netfilter/ip6_tables.c
@@ -396,10 +396,13 @@ mark_source_chains(const struct xt_table_info *newinfo,
for (hook = 0; hook < NF_INET_NUMHOOKS; hook++) {
unsigned int pos = newinfo->hook_entry[hook];
struct ip6t_entry *e = entry0 + pos;
+ unsigned int last_pos, depth;
if (!(valid_hooks & (1 << hook)))
continue;
+ depth = 0;
+ last_pos = pos;
/* Set initial back pointer. */
e->counters.pcnt = pos;
@@ -428,6 +431,8 @@ mark_source_chains(const struct xt_table_info *newinfo,
pos = e->counters.pcnt;
e->counters.pcnt = 0;
+ if (depth)
+ --depth;
/* We're at the start. */
if (pos == oldpos)
goto next;
@@ -452,6 +457,9 @@ mark_source_chains(const struct xt_table_info *newinfo,
if (!xt_find_jump_offset(offsets, newpos,
newinfo->number))
return 0;
+
+ if (entry0 + newpos != ip6t_next_entry(e))
+ ++depth;
} else {
/* ... this is a fallthru */
newpos = pos + e->next_offset;
@@ -462,8 +470,15 @@ mark_source_chains(const struct xt_table_info *newinfo,
e->counters.pcnt = pos;
pos = newpos;
}
+ if (depth == 0)
+ last_pos = pos;
+ }
+next:
+ if (last_pos != newinfo->underflow[hook]) {
+ pr_err_ratelimited("last base chain position %u doesn't match underflow %u (hook %u)\n",
+ last_pos, newinfo->underflow[hook], hook);
+ return 0;
}
-next: ;
}
return 1;
}
--
2.11.0
^ permalink raw reply related
* [PATCH 19/30] netfilter: xt_limit: Spelling s/maxmum/maximum/
From: Pablo Neira Ayuso @ 2018-03-12 17:59 UTC (permalink / raw)
To: netfilter-devel; +Cc: davem, netdev
In-Reply-To: <20180312175920.9022-1-pablo@netfilter.org>
From: Geert Uytterhoeven <geert+renesas@glider.be>
Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
net/netfilter/xt_limit.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/net/netfilter/xt_limit.c b/net/netfilter/xt_limit.c
index 55d18cd67635..9f098ecb2449 100644
--- a/net/netfilter/xt_limit.c
+++ b/net/netfilter/xt_limit.c
@@ -46,7 +46,7 @@ MODULE_ALIAS("ip6t_limit");
See Alexey's formal explanation in net/sched/sch_tbf.c.
- To get the maxmum range, we multiply by this factor (ie. you get N
+ To get the maximum range, we multiply by this factor (ie. you get N
credits per jiffy). We want to allow a rate as low as 1 per day
(slowest userspace tool allows), which means
CREDITS_PER_JIFFY*HZ*60*60*24 < 2^32. ie. */
--
2.11.0
^ permalink raw reply related
* [PATCH 18/30] netfilter: make xt_rateest hash table per net
From: Pablo Neira Ayuso @ 2018-03-12 17:59 UTC (permalink / raw)
To: netfilter-devel; +Cc: davem, netdev
In-Reply-To: <20180312175920.9022-1-pablo@netfilter.org>
From: Cong Wang <xiyou.wangcong@gmail.com>
As suggested by Eric, we need to make the xt_rateest
hash table and its lock per netns to reduce lock
contentions.
Cc: Florian Westphal <fw@strlen.de>
Cc: Eric Dumazet <edumazet@google.com>
Cc: Pablo Neira Ayuso <pablo@netfilter.org>
Signed-off-by: Cong Wang <xiyou.wangcong@gmail.com>
Reviewed-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
include/net/netfilter/xt_rateest.h | 4 +-
net/netfilter/xt_RATEEST.c | 91 +++++++++++++++++++++++++++-----------
net/netfilter/xt_rateest.c | 10 ++---
3 files changed, 72 insertions(+), 33 deletions(-)
diff --git a/include/net/netfilter/xt_rateest.h b/include/net/netfilter/xt_rateest.h
index b1db13772554..832ab69efda5 100644
--- a/include/net/netfilter/xt_rateest.h
+++ b/include/net/netfilter/xt_rateest.h
@@ -21,7 +21,7 @@ struct xt_rateest {
struct net_rate_estimator __rcu *rate_est;
};
-struct xt_rateest *xt_rateest_lookup(const char *name);
-void xt_rateest_put(struct xt_rateest *est);
+struct xt_rateest *xt_rateest_lookup(struct net *net, const char *name);
+void xt_rateest_put(struct net *net, struct xt_rateest *est);
#endif /* _XT_RATEEST_H */
diff --git a/net/netfilter/xt_RATEEST.c b/net/netfilter/xt_RATEEST.c
index 141c295191f6..dec843cadf46 100644
--- a/net/netfilter/xt_RATEEST.c
+++ b/net/netfilter/xt_RATEEST.c
@@ -14,15 +14,21 @@
#include <linux/slab.h>
#include <net/gen_stats.h>
#include <net/netlink.h>
+#include <net/netns/generic.h>
#include <linux/netfilter/x_tables.h>
#include <linux/netfilter/xt_RATEEST.h>
#include <net/netfilter/xt_rateest.h>
-static DEFINE_MUTEX(xt_rateest_mutex);
-
#define RATEEST_HSIZE 16
-static struct hlist_head rateest_hash[RATEEST_HSIZE] __read_mostly;
+
+struct xt_rateest_net {
+ struct mutex hash_lock;
+ struct hlist_head hash[RATEEST_HSIZE];
+};
+
+static unsigned int xt_rateest_id;
+
static unsigned int jhash_rnd __read_mostly;
static unsigned int xt_rateest_hash(const char *name)
@@ -31,21 +37,23 @@ static unsigned int xt_rateest_hash(const char *name)
(RATEEST_HSIZE - 1);
}
-static void xt_rateest_hash_insert(struct xt_rateest *est)
+static void xt_rateest_hash_insert(struct xt_rateest_net *xn,
+ struct xt_rateest *est)
{
unsigned int h;
h = xt_rateest_hash(est->name);
- hlist_add_head(&est->list, &rateest_hash[h]);
+ hlist_add_head(&est->list, &xn->hash[h]);
}
-static struct xt_rateest *__xt_rateest_lookup(const char *name)
+static struct xt_rateest *__xt_rateest_lookup(struct xt_rateest_net *xn,
+ const char *name)
{
struct xt_rateest *est;
unsigned int h;
h = xt_rateest_hash(name);
- hlist_for_each_entry(est, &rateest_hash[h], list) {
+ hlist_for_each_entry(est, &xn->hash[h], list) {
if (strcmp(est->name, name) == 0) {
est->refcnt++;
return est;
@@ -55,20 +63,23 @@ static struct xt_rateest *__xt_rateest_lookup(const char *name)
return NULL;
}
-struct xt_rateest *xt_rateest_lookup(const char *name)
+struct xt_rateest *xt_rateest_lookup(struct net *net, const char *name)
{
+ struct xt_rateest_net *xn = net_generic(net, xt_rateest_id);
struct xt_rateest *est;
- mutex_lock(&xt_rateest_mutex);
- est = __xt_rateest_lookup(name);
- mutex_unlock(&xt_rateest_mutex);
+ mutex_lock(&xn->hash_lock);
+ est = __xt_rateest_lookup(xn, name);
+ mutex_unlock(&xn->hash_lock);
return est;
}
EXPORT_SYMBOL_GPL(xt_rateest_lookup);
-void xt_rateest_put(struct xt_rateest *est)
+void xt_rateest_put(struct net *net, struct xt_rateest *est)
{
- mutex_lock(&xt_rateest_mutex);
+ struct xt_rateest_net *xn = net_generic(net, xt_rateest_id);
+
+ mutex_lock(&xn->hash_lock);
if (--est->refcnt == 0) {
hlist_del(&est->list);
gen_kill_estimator(&est->rate_est);
@@ -78,7 +89,7 @@ void xt_rateest_put(struct xt_rateest *est)
*/
kfree_rcu(est, rcu);
}
- mutex_unlock(&xt_rateest_mutex);
+ mutex_unlock(&xn->hash_lock);
}
EXPORT_SYMBOL_GPL(xt_rateest_put);
@@ -98,6 +109,7 @@ xt_rateest_tg(struct sk_buff *skb, const struct xt_action_param *par)
static int xt_rateest_tg_checkentry(const struct xt_tgchk_param *par)
{
+ struct xt_rateest_net *xn = net_generic(par->net, xt_rateest_id);
struct xt_rateest_target_info *info = par->targinfo;
struct xt_rateest *est;
struct {
@@ -108,10 +120,10 @@ static int xt_rateest_tg_checkentry(const struct xt_tgchk_param *par)
net_get_random_once(&jhash_rnd, sizeof(jhash_rnd));
- mutex_lock(&xt_rateest_mutex);
- est = __xt_rateest_lookup(info->name);
+ mutex_lock(&xn->hash_lock);
+ est = __xt_rateest_lookup(xn, info->name);
if (est) {
- mutex_unlock(&xt_rateest_mutex);
+ mutex_unlock(&xn->hash_lock);
/*
* If estimator parameters are specified, they must match the
* existing estimator.
@@ -119,7 +131,7 @@ static int xt_rateest_tg_checkentry(const struct xt_tgchk_param *par)
if ((!info->interval && !info->ewma_log) ||
(info->interval != est->params.interval ||
info->ewma_log != est->params.ewma_log)) {
- xt_rateest_put(est);
+ xt_rateest_put(par->net, est);
return -EINVAL;
}
info->est = est;
@@ -148,14 +160,14 @@ static int xt_rateest_tg_checkentry(const struct xt_tgchk_param *par)
goto err2;
info->est = est;
- xt_rateest_hash_insert(est);
- mutex_unlock(&xt_rateest_mutex);
+ xt_rateest_hash_insert(xn, est);
+ mutex_unlock(&xn->hash_lock);
return 0;
err2:
kfree(est);
err1:
- mutex_unlock(&xt_rateest_mutex);
+ mutex_unlock(&xn->hash_lock);
return ret;
}
@@ -163,7 +175,7 @@ static void xt_rateest_tg_destroy(const struct xt_tgdtor_param *par)
{
struct xt_rateest_target_info *info = par->targinfo;
- xt_rateest_put(info->est);
+ xt_rateest_put(par->net, info->est);
}
static struct xt_target xt_rateest_tg_reg __read_mostly = {
@@ -178,19 +190,46 @@ static struct xt_target xt_rateest_tg_reg __read_mostly = {
.me = THIS_MODULE,
};
-static int __init xt_rateest_tg_init(void)
+static __net_init int xt_rateest_net_init(struct net *net)
+{
+ struct xt_rateest_net *xn = net_generic(net, xt_rateest_id);
+ int i;
+
+ mutex_init(&xn->hash_lock);
+ for (i = 0; i < ARRAY_SIZE(xn->hash); i++)
+ INIT_HLIST_HEAD(&xn->hash[i]);
+ return 0;
+}
+
+static void __net_exit xt_rateest_net_exit(struct net *net)
{
- unsigned int i;
+ struct xt_rateest_net *xn = net_generic(net, xt_rateest_id);
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(xn->hash); i++)
+ WARN_ON_ONCE(!hlist_empty(&xn->hash[i]));
+}
- for (i = 0; i < ARRAY_SIZE(rateest_hash); i++)
- INIT_HLIST_HEAD(&rateest_hash[i]);
+static struct pernet_operations xt_rateest_net_ops = {
+ .init = xt_rateest_net_init,
+ .exit = xt_rateest_net_exit,
+ .id = &xt_rateest_id,
+ .size = sizeof(struct xt_rateest_net),
+};
+
+static int __init xt_rateest_tg_init(void)
+{
+ int err = register_pernet_subsys(&xt_rateest_net_ops);
+ if (err)
+ return err;
return xt_register_target(&xt_rateest_tg_reg);
}
static void __exit xt_rateest_tg_fini(void)
{
xt_unregister_target(&xt_rateest_tg_reg);
+ unregister_pernet_subsys(&xt_rateest_net_ops);
}
diff --git a/net/netfilter/xt_rateest.c b/net/netfilter/xt_rateest.c
index 755d2f6693a2..bf77326861af 100644
--- a/net/netfilter/xt_rateest.c
+++ b/net/netfilter/xt_rateest.c
@@ -95,13 +95,13 @@ static int xt_rateest_mt_checkentry(const struct xt_mtchk_param *par)
}
ret = -ENOENT;
- est1 = xt_rateest_lookup(info->name1);
+ est1 = xt_rateest_lookup(par->net, info->name1);
if (!est1)
goto err1;
est2 = NULL;
if (info->flags & XT_RATEEST_MATCH_REL) {
- est2 = xt_rateest_lookup(info->name2);
+ est2 = xt_rateest_lookup(par->net, info->name2);
if (!est2)
goto err2;
}
@@ -111,7 +111,7 @@ static int xt_rateest_mt_checkentry(const struct xt_mtchk_param *par)
return 0;
err2:
- xt_rateest_put(est1);
+ xt_rateest_put(par->net, est1);
err1:
return ret;
}
@@ -120,9 +120,9 @@ static void xt_rateest_mt_destroy(const struct xt_mtdtor_param *par)
{
struct xt_rateest_match_info *info = par->matchinfo;
- xt_rateest_put(info->est1);
+ xt_rateest_put(par->net, info->est1);
if (info->est2)
- xt_rateest_put(info->est2);
+ xt_rateest_put(par->net, info->est2);
}
static struct xt_match xt_rateest_mt_reg __read_mostly = {
--
2.11.0
^ permalink raw reply related
* [PATCH 21/30] netfilter: nf_flow_table: clean up flow_offload_alloc
From: Pablo Neira Ayuso @ 2018-03-12 17:59 UTC (permalink / raw)
To: netfilter-devel; +Cc: davem, netdev
In-Reply-To: <20180312175920.9022-1-pablo@netfilter.org>
From: Felix Fietkau <nbd@nbd.name>
Reduce code duplication and make it much easier to read
Signed-off-by: Felix Fietkau <nbd@nbd.name>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
net/netfilter/nf_flow_table.c | 93 ++++++++++++++++---------------------------
1 file changed, 34 insertions(+), 59 deletions(-)
diff --git a/net/netfilter/nf_flow_table.c b/net/netfilter/nf_flow_table.c
index ec410cae9307..db0673a40b97 100644
--- a/net/netfilter/nf_flow_table.c
+++ b/net/netfilter/nf_flow_table.c
@@ -16,6 +16,38 @@ struct flow_offload_entry {
struct rcu_head rcu_head;
};
+static void
+flow_offload_fill_dir(struct flow_offload *flow, struct nf_conn *ct,
+ struct nf_flow_route *route,
+ enum flow_offload_tuple_dir dir)
+{
+ struct flow_offload_tuple *ft = &flow->tuplehash[dir].tuple;
+ struct nf_conntrack_tuple *ctt = &ct->tuplehash[dir].tuple;
+
+ ft->dir = dir;
+
+ switch (ctt->src.l3num) {
+ case NFPROTO_IPV4:
+ ft->src_v4 = ctt->src.u3.in;
+ ft->dst_v4 = ctt->dst.u3.in;
+ break;
+ case NFPROTO_IPV6:
+ ft->src_v6 = ctt->src.u3.in6;
+ ft->dst_v6 = ctt->dst.u3.in6;
+ break;
+ }
+
+ ft->l3proto = ctt->src.l3num;
+ ft->l4proto = ctt->dst.protonum;
+ ft->src_port = ctt->src.u.tcp.port;
+ ft->dst_port = ctt->dst.u.tcp.port;
+
+ ft->iifidx = route->tuple[dir].ifindex;
+ ft->oifidx = route->tuple[!dir].ifindex;
+
+ ft->dst_cache = route->tuple[dir].dst;
+}
+
struct flow_offload *
flow_offload_alloc(struct nf_conn *ct, struct nf_flow_route *route)
{
@@ -40,65 +72,8 @@ flow_offload_alloc(struct nf_conn *ct, struct nf_flow_route *route)
entry->ct = ct;
- switch (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num) {
- case NFPROTO_IPV4:
- flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].tuple.src_v4 =
- ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.in;
- flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].tuple.dst_v4 =
- ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u3.in;
- flow->tuplehash[FLOW_OFFLOAD_DIR_REPLY].tuple.src_v4 =
- ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3.in;
- flow->tuplehash[FLOW_OFFLOAD_DIR_REPLY].tuple.dst_v4 =
- ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.in;
- break;
- case NFPROTO_IPV6:
- flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].tuple.src_v6 =
- ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.in6;
- flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].tuple.dst_v6 =
- ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u3.in6;
- flow->tuplehash[FLOW_OFFLOAD_DIR_REPLY].tuple.src_v6 =
- ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3.in6;
- flow->tuplehash[FLOW_OFFLOAD_DIR_REPLY].tuple.dst_v6 =
- ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.in6;
- break;
- }
-
- flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].tuple.l3proto =
- ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num;
- flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].tuple.l4proto =
- ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum;
- flow->tuplehash[FLOW_OFFLOAD_DIR_REPLY].tuple.l3proto =
- ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num;
- flow->tuplehash[FLOW_OFFLOAD_DIR_REPLY].tuple.l4proto =
- ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum;
-
- flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].tuple.dst_cache =
- route->tuple[FLOW_OFFLOAD_DIR_ORIGINAL].dst;
- flow->tuplehash[FLOW_OFFLOAD_DIR_REPLY].tuple.dst_cache =
- route->tuple[FLOW_OFFLOAD_DIR_REPLY].dst;
-
- flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].tuple.src_port =
- ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.tcp.port;
- flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].tuple.dst_port =
- ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.tcp.port;
- flow->tuplehash[FLOW_OFFLOAD_DIR_REPLY].tuple.src_port =
- ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u.tcp.port;
- flow->tuplehash[FLOW_OFFLOAD_DIR_REPLY].tuple.dst_port =
- ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.tcp.port;
-
- flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].tuple.dir =
- FLOW_OFFLOAD_DIR_ORIGINAL;
- flow->tuplehash[FLOW_OFFLOAD_DIR_REPLY].tuple.dir =
- FLOW_OFFLOAD_DIR_REPLY;
-
- flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].tuple.iifidx =
- route->tuple[FLOW_OFFLOAD_DIR_ORIGINAL].ifindex;
- flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].tuple.oifidx =
- route->tuple[FLOW_OFFLOAD_DIR_REPLY].ifindex;
- flow->tuplehash[FLOW_OFFLOAD_DIR_REPLY].tuple.iifidx =
- route->tuple[FLOW_OFFLOAD_DIR_REPLY].ifindex;
- flow->tuplehash[FLOW_OFFLOAD_DIR_REPLY].tuple.oifidx =
- route->tuple[FLOW_OFFLOAD_DIR_ORIGINAL].ifindex;
+ flow_offload_fill_dir(flow, ct, route, FLOW_OFFLOAD_DIR_ORIGINAL);
+ flow_offload_fill_dir(flow, ct, route, FLOW_OFFLOAD_DIR_REPLY);
if (ct->status & IPS_SRC_NAT)
flow->flags |= FLOW_OFFLOAD_SNAT;
--
2.11.0
^ permalink raw reply related
* [PATCH 20/30] netfilter: nf_flow_table: use IP_CT_DIR_* values for FLOW_OFFLOAD_DIR_*
From: Pablo Neira Ayuso @ 2018-03-12 17:59 UTC (permalink / raw)
To: netfilter-devel; +Cc: davem, netdev
In-Reply-To: <20180312175920.9022-1-pablo@netfilter.org>
From: Felix Fietkau <nbd@nbd.name>
Simplifies further code cleanups
Signed-off-by: Felix Fietkau <nbd@nbd.name>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
include/net/netfilter/nf_flow_table.h | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/include/net/netfilter/nf_flow_table.h b/include/net/netfilter/nf_flow_table.h
index 833752dd0c58..09ba67598991 100644
--- a/include/net/netfilter/nf_flow_table.h
+++ b/include/net/netfilter/nf_flow_table.h
@@ -6,6 +6,7 @@
#include <linux/netdevice.h>
#include <linux/rhashtable.h>
#include <linux/rcupdate.h>
+#include <linux/netfilter/nf_conntrack_tuple_common.h>
#include <net/dst.h>
struct nf_flowtable;
@@ -27,11 +28,10 @@ struct nf_flowtable {
};
enum flow_offload_tuple_dir {
- FLOW_OFFLOAD_DIR_ORIGINAL,
- FLOW_OFFLOAD_DIR_REPLY,
- __FLOW_OFFLOAD_DIR_MAX = FLOW_OFFLOAD_DIR_REPLY,
+ FLOW_OFFLOAD_DIR_ORIGINAL = IP_CT_DIR_ORIGINAL,
+ FLOW_OFFLOAD_DIR_REPLY = IP_CT_DIR_REPLY,
+ FLOW_OFFLOAD_DIR_MAX = IP_CT_DIR_MAX
};
-#define FLOW_OFFLOAD_DIR_MAX (__FLOW_OFFLOAD_DIR_MAX + 1)
struct flow_offload_tuple {
union {
--
2.11.0
^ permalink raw reply related
* [PATCH 22/30] ipv6: make ip6_dst_mtu_forward inline
From: Pablo Neira Ayuso @ 2018-03-12 17:59 UTC (permalink / raw)
To: netfilter-devel; +Cc: davem, netdev
In-Reply-To: <20180312175920.9022-1-pablo@netfilter.org>
From: Felix Fietkau <nbd@nbd.name>
Needed to remove a direct dependency on ipv6.ko from flowtable
infrastructure. Make it inline like ip_dst_mtu_maybe_forward().
Signed-off-by: Felix Fietkau <nbd@nbd.name>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
include/net/ip6_route.h | 21 +++++++++++++++++++++
include/net/ipv6.h | 2 --
net/ipv6/ip6_output.c | 22 ----------------------
3 files changed, 21 insertions(+), 24 deletions(-)
diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h
index ce2abc0ff102..18ef8c9890e2 100644
--- a/include/net/ip6_route.h
+++ b/include/net/ip6_route.h
@@ -271,4 +271,25 @@ static inline bool rt6_duplicate_nexthop(struct rt6_info *a, struct rt6_info *b)
!lwtunnel_cmp_encap(a->dst.lwtstate, b->dst.lwtstate);
}
+static inline unsigned int ip6_dst_mtu_forward(const struct dst_entry *dst)
+{
+ unsigned int mtu;
+ struct inet6_dev *idev;
+
+ if (dst_metric_locked(dst, RTAX_MTU)) {
+ mtu = dst_metric_raw(dst, RTAX_MTU);
+ if (mtu)
+ return mtu;
+ }
+
+ mtu = IPV6_MIN_MTU;
+ rcu_read_lock();
+ idev = __in6_dev_get(dst->dev);
+ if (idev)
+ mtu = idev->cnf.mtu6;
+ rcu_read_unlock();
+
+ return mtu;
+}
+
#endif
diff --git a/include/net/ipv6.h b/include/net/ipv6.h
index cabd3cdd4015..a4089cebe8d3 100644
--- a/include/net/ipv6.h
+++ b/include/net/ipv6.h
@@ -970,8 +970,6 @@ static inline struct sk_buff *ip6_finish_skb(struct sock *sk)
&inet6_sk(sk)->cork);
}
-unsigned int ip6_dst_mtu_forward(const struct dst_entry *dst);
-
int ip6_dst_lookup(struct net *net, struct sock *sk, struct dst_entry **dst,
struct flowi6 *fl6);
struct dst_entry *ip6_dst_lookup_flow(const struct sock *sk, struct flowi6 *fl6,
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index a6eb0e699b15..2f1de4e8132a 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -378,28 +378,6 @@ static inline int ip6_forward_finish(struct net *net, struct sock *sk,
return dst_output(net, sk, skb);
}
-unsigned int ip6_dst_mtu_forward(const struct dst_entry *dst)
-{
- unsigned int mtu;
- struct inet6_dev *idev;
-
- if (dst_metric_locked(dst, RTAX_MTU)) {
- mtu = dst_metric_raw(dst, RTAX_MTU);
- if (mtu)
- return mtu;
- }
-
- mtu = IPV6_MIN_MTU;
- rcu_read_lock();
- idev = __in6_dev_get(dst->dev);
- if (idev)
- mtu = idev->cnf.mtu6;
- rcu_read_unlock();
-
- return mtu;
-}
-EXPORT_SYMBOL_GPL(ip6_dst_mtu_forward);
-
static bool ip6_pkt_too_big(const struct sk_buff *skb, unsigned int mtu)
{
if (skb->len <= mtu)
--
2.11.0
^ permalink raw reply related
* [PATCH 23/30] netfilter: nf_flow_table: cache mtu in struct flow_offload_tuple
From: Pablo Neira Ayuso @ 2018-03-12 17:59 UTC (permalink / raw)
To: netfilter-devel; +Cc: davem, netdev
In-Reply-To: <20180312175920.9022-1-pablo@netfilter.org>
From: Felix Fietkau <nbd@nbd.name>
Reduces the number of cache lines touched in the offload forwarding
path. This is safe because PMTU limits are bypassed for the forwarding
path (see commit f87c10a8aa1e for more details).
Signed-off-by: Felix Fietkau <nbd@nbd.name>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
include/net/netfilter/nf_flow_table.h | 2 ++
net/ipv4/netfilter/nf_flow_table_ipv4.c | 17 +++--------------
net/ipv6/netfilter/nf_flow_table_ipv6.c | 17 +++--------------
net/netfilter/nf_flow_table.c | 8 ++++++--
4 files changed, 14 insertions(+), 30 deletions(-)
diff --git a/include/net/netfilter/nf_flow_table.h b/include/net/netfilter/nf_flow_table.h
index 09ba67598991..76ee5c81b752 100644
--- a/include/net/netfilter/nf_flow_table.h
+++ b/include/net/netfilter/nf_flow_table.h
@@ -55,6 +55,8 @@ struct flow_offload_tuple {
int oifidx;
+ u16 mtu;
+
struct dst_entry *dst_cache;
};
diff --git a/net/ipv4/netfilter/nf_flow_table_ipv4.c b/net/ipv4/netfilter/nf_flow_table_ipv4.c
index 25d2975da156..e17ef57b0df4 100644
--- a/net/ipv4/netfilter/nf_flow_table_ipv4.c
+++ b/net/ipv4/netfilter/nf_flow_table_ipv4.c
@@ -177,7 +177,7 @@ static int nf_flow_tuple_ip(struct sk_buff *skb, const struct net_device *dev,
}
/* Based on ip_exceeds_mtu(). */
-static bool __nf_flow_exceeds_mtu(const struct sk_buff *skb, unsigned int mtu)
+static bool nf_flow_exceeds_mtu(const struct sk_buff *skb, unsigned int mtu)
{
if (skb->len <= mtu)
return false;
@@ -191,17 +191,6 @@ static bool __nf_flow_exceeds_mtu(const struct sk_buff *skb, unsigned int mtu)
return true;
}
-static bool nf_flow_exceeds_mtu(struct sk_buff *skb, const struct rtable *rt)
-{
- u32 mtu;
-
- mtu = ip_dst_mtu_maybe_forward(&rt->dst, true);
- if (__nf_flow_exceeds_mtu(skb, mtu))
- return true;
-
- return false;
-}
-
unsigned int
nf_flow_offload_ip_hook(void *priv, struct sk_buff *skb,
const struct nf_hook_state *state)
@@ -232,9 +221,9 @@ nf_flow_offload_ip_hook(void *priv, struct sk_buff *skb,
dir = tuplehash->tuple.dir;
flow = container_of(tuplehash, struct flow_offload, tuplehash[dir]);
-
rt = (const struct rtable *)flow->tuplehash[dir].tuple.dst_cache;
- if (unlikely(nf_flow_exceeds_mtu(skb, rt)))
+
+ if (unlikely(nf_flow_exceeds_mtu(skb, flow->tuplehash[dir].tuple.mtu)))
return NF_ACCEPT;
if (skb_try_make_writable(skb, sizeof(*iph)))
diff --git a/net/ipv6/netfilter/nf_flow_table_ipv6.c b/net/ipv6/netfilter/nf_flow_table_ipv6.c
index d346705d6ee6..f530efd3e378 100644
--- a/net/ipv6/netfilter/nf_flow_table_ipv6.c
+++ b/net/ipv6/netfilter/nf_flow_table_ipv6.c
@@ -173,7 +173,7 @@ static int nf_flow_tuple_ipv6(struct sk_buff *skb, const struct net_device *dev,
}
/* Based on ip_exceeds_mtu(). */
-static bool __nf_flow_exceeds_mtu(const struct sk_buff *skb, unsigned int mtu)
+static bool nf_flow_exceeds_mtu(const struct sk_buff *skb, unsigned int mtu)
{
if (skb->len <= mtu)
return false;
@@ -184,17 +184,6 @@ static bool __nf_flow_exceeds_mtu(const struct sk_buff *skb, unsigned int mtu)
return true;
}
-static bool nf_flow_exceeds_mtu(struct sk_buff *skb, const struct rt6_info *rt)
-{
- u32 mtu;
-
- mtu = ip6_dst_mtu_forward(&rt->dst);
- if (__nf_flow_exceeds_mtu(skb, mtu))
- return true;
-
- return false;
-}
-
unsigned int
nf_flow_offload_ipv6_hook(void *priv, struct sk_buff *skb,
const struct nf_hook_state *state)
@@ -225,9 +214,9 @@ nf_flow_offload_ipv6_hook(void *priv, struct sk_buff *skb,
dir = tuplehash->tuple.dir;
flow = container_of(tuplehash, struct flow_offload, tuplehash[dir]);
-
rt = (struct rt6_info *)flow->tuplehash[dir].tuple.dst_cache;
- if (unlikely(nf_flow_exceeds_mtu(skb, rt)))
+
+ if (unlikely(nf_flow_exceeds_mtu(skb, flow->tuplehash[dir].tuple.mtu)))
return NF_ACCEPT;
if (skb_try_make_writable(skb, sizeof(*ip6h)))
diff --git a/net/netfilter/nf_flow_table.c b/net/netfilter/nf_flow_table.c
index db0673a40b97..7403a0dfddf7 100644
--- a/net/netfilter/nf_flow_table.c
+++ b/net/netfilter/nf_flow_table.c
@@ -4,6 +4,8 @@
#include <linux/netfilter.h>
#include <linux/rhashtable.h>
#include <linux/netdevice.h>
+#include <net/ip.h>
+#include <net/ip6_route.h>
#include <net/netfilter/nf_tables.h>
#include <net/netfilter/nf_flow_table.h>
#include <net/netfilter/nf_conntrack.h>
@@ -23,6 +25,7 @@ flow_offload_fill_dir(struct flow_offload *flow, struct nf_conn *ct,
{
struct flow_offload_tuple *ft = &flow->tuplehash[dir].tuple;
struct nf_conntrack_tuple *ctt = &ct->tuplehash[dir].tuple;
+ struct dst_entry *dst = route->tuple[dir].dst;
ft->dir = dir;
@@ -30,10 +33,12 @@ flow_offload_fill_dir(struct flow_offload *flow, struct nf_conn *ct,
case NFPROTO_IPV4:
ft->src_v4 = ctt->src.u3.in;
ft->dst_v4 = ctt->dst.u3.in;
+ ft->mtu = ip_dst_mtu_maybe_forward(dst, true);
break;
case NFPROTO_IPV6:
ft->src_v6 = ctt->src.u3.in6;
ft->dst_v6 = ctt->dst.u3.in6;
+ ft->mtu = ip6_dst_mtu_forward(dst);
break;
}
@@ -44,8 +49,7 @@ flow_offload_fill_dir(struct flow_offload *flow, struct nf_conn *ct,
ft->iifidx = route->tuple[dir].ifindex;
ft->oifidx = route->tuple[!dir].ifindex;
-
- ft->dst_cache = route->tuple[dir].dst;
+ ft->dst_cache = dst;
}
struct flow_offload *
--
2.11.0
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox