--- /dev/null
+From 9782a11efc072faaf91d4aa60e9d23553f918029 Mon Sep 17 00:00:00 2001
+From: Florian Westphal <fw@strlen.de>
+Date: Tue, 27 Feb 2018 19:42:34 +0100
+Subject: netfilter: compat: prepare xt_compat_init_offsets to return errors
+
+From: Florian Westphal <fw@strlen.de>
+
+commit 9782a11efc072faaf91d4aa60e9d23553f918029 upstream.
+
+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>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.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(-)
+
+--- 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);
+--- a/net/bridge/netfilter/ebtables.c
++++ b/net/bridge/netfilter/ebtables.c
+@@ -1821,10 +1821,14 @@ static int compat_table_info(const struc
+ {
+ 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);
+ }
+@@ -2268,7 +2272,9 @@ static int compat_do_replace(struct net
+
+ 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;
+--- a/net/ipv4/netfilter/arp_tables.c
++++ b/net/ipv4/netfilter/arp_tables.c
+@@ -781,7 +781,9 @@ static int compat_table_info(const struc
+ 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)
+@@ -1167,7 +1169,7 @@ static int translate_compat_table(struct
+ struct compat_arpt_entry *iter0;
+ struct arpt_replace repl;
+ unsigned int size;
+- int ret = 0;
++ int ret;
+
+ info = *pinfo;
+ entry0 = *pentry0;
+@@ -1176,7 +1178,9 @@ static int translate_compat_table(struct
+
+ 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,
+--- a/net/ipv4/netfilter/ip_tables.c
++++ b/net/ipv4/netfilter/ip_tables.c
+@@ -945,7 +945,9 @@ static int compat_table_info(const struc
+ 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)
+@@ -1418,7 +1420,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,
+--- a/net/ipv6/netfilter/ip6_tables.c
++++ b/net/ipv6/netfilter/ip6_tables.c
+@@ -962,7 +962,9 @@ static int compat_table_info(const struc
+ 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)
+@@ -1425,7 +1427,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;
+@@ -1434,7 +1436,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,
+--- a/net/netfilter/x_tables.c
++++ b/net/netfilter/x_tables.c
+@@ -604,10 +604,12 @@ int xt_compat_calc_jump(u_int8_t af, uns
+ }
+ 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);
+
--- /dev/null
+From 7d7d7e02111e9a4dc9d0658597f528f815d820fd Mon Sep 17 00:00:00 2001
+From: Florian Westphal <fw@strlen.de>
+Date: Tue, 27 Feb 2018 19:42:35 +0100
+Subject: netfilter: compat: reject huge allocation requests
+
+From: Florian Westphal <fw@strlen.de>
+
+commit 7d7d7e02111e9a4dc9d0658597f528f815d820fd upstream.
+
+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>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ net/netfilter/x_tables.c | 26 ++++++++++++++++++--------
+ 1 file changed, 18 insertions(+), 8 deletions(-)
+
+--- a/net/netfilter/x_tables.c
++++ b/net/netfilter/x_tables.c
+@@ -554,14 +554,8 @@ int xt_compat_add_offset(u_int8_t af, un
+ {
+ 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;
+@@ -606,6 +600,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;
+
--- /dev/null
+From c84ca954ac9fa67a6ce27f91f01e4451c74fd8f6 Mon Sep 17 00:00:00 2001
+From: Florian Westphal <fw@strlen.de>
+Date: Tue, 27 Feb 2018 19:42:33 +0100
+Subject: netfilter: x_tables: add counters allocation wrapper
+
+From: Florian Westphal <fw@strlen.de>
+
+commit c84ca954ac9fa67a6ce27f91f01e4451c74fd8f6 upstream.
+
+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>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.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(-)
+
+--- 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, co
+
+ 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,
+--- a/net/ipv4/netfilter/arp_tables.c
++++ b/net/ipv4/netfilter/arp_tables.c
+@@ -895,7 +895,7 @@ static int __do_replace(struct net *net,
+ 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;
+--- a/net/ipv4/netfilter/ip_tables.c
++++ b/net/ipv4/netfilter/ip_tables.c
+@@ -1057,7 +1057,7 @@ __do_replace(struct net *net, const char
+ 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;
+--- a/net/ipv6/netfilter/ip6_tables.c
++++ b/net/ipv6/netfilter/ip6_tables.c
+@@ -1075,7 +1075,7 @@ __do_replace(struct net *net, const char
+ 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;
+--- a/net/netfilter/x_tables.c
++++ b/net/netfilter/x_tables.c
+@@ -1199,6 +1199,21 @@ static int xt_jumpstack_alloc(struct xt_
+ 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,
--- /dev/null
+From 19926968ea86a286aa6fbea16ee3f2e7442f10f0 Mon Sep 17 00:00:00 2001
+From: Florian Westphal <fw@strlen.de>
+Date: Tue, 27 Feb 2018 19:42:31 +0100
+Subject: netfilter: x_tables: cap allocations at 512 mbyte
+
+From: Florian Westphal <fw@strlen.de>
+
+commit 19926968ea86a286aa6fbea16ee3f2e7442f10f0 upstream.
+
+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>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ net/netfilter/x_tables.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/net/netfilter/x_tables.c
++++ b/net/netfilter/x_tables.c
+@@ -40,6 +40,7 @@ MODULE_AUTHOR("Harald Welte <laforge@net
+ 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 */
+@@ -1029,7 +1030,7 @@ struct xt_table_info *xt_alloc_table_inf
+ 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