netfilter: ebtables: fix table blob use-after-free
authorFlorian Westphal <fw@strlen.de>
Fri, 17 Feb 2023 22:20:06 +0000 (23:20 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 11 Mar 2023 12:57:28 +0000 (13:57 +0100)
[ Upstream commit e58a171d35e32e6e8c37cfe0e8a94406732a331f ]

We are not allowed to return an error at this point.
Looking at the code it looks like ret is always 0 at this
point, but its not.

t = find_table_lock(net, repl->name, &ret, &ebt_mutex);

... this can return a valid table, with ret != 0.

This bug causes update of table->private with the new
blob, but then frees the blob right away in the caller.

Syzbot report:

BUG: KASAN: vmalloc-out-of-bounds in __ebt_unregister_table+0xc00/0xcd0 net/bridge/netfilter/ebtables.c:1168
Read of size 4 at addr ffffc90005425000 by task kworker/u4:4/74
Workqueue: netns cleanup_net
Call Trace:
 kasan_report+0xbf/0x1f0 mm/kasan/report.c:517
 __ebt_unregister_table+0xc00/0xcd0 net/bridge/netfilter/ebtables.c:1168
 ebt_unregister_table+0x35/0x40 net/bridge/netfilter/ebtables.c:1372
 ops_exit_list+0xb0/0x170 net/core/net_namespace.c:169
 cleanup_net+0x4ee/0xb10 net/core/net_namespace.c:613
...

ip(6)tables appears to be ok (ret should be 0 at this point) but make
this more obvious.

Fixes: c58dd2dd443c ("netfilter: Can't fail and free after table replacement")
Reported-by: syzbot+f61594de72d6705aea03@syzkaller.appspotmail.com
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
net/bridge/netfilter/ebtables.c
net/ipv4/netfilter/ip_tables.c
net/ipv6/netfilter/ip6_tables.c

index 16774559c52cb300a03a9610e7eaff7d10b23e49..a09b2fc11c80e018d8149d68de737a4aa5aba007 100644 (file)
@@ -1090,7 +1090,7 @@ static int do_replace_finish(struct net *net, struct ebt_replace *repl,
 
        audit_log_nfcfg(repl->name, AF_BRIDGE, repl->nentries,
                        AUDIT_XT_OP_REPLACE, GFP_KERNEL);
-       return ret;
+       return 0;
 
 free_unlock:
        mutex_unlock(&ebt_mutex);
index 13acb687c19ab7c8e969f6077a937f320d43c12f..91301dc3924a2c7948bb1e0a288e771c94e50261 100644 (file)
@@ -1044,7 +1044,6 @@ __do_replace(struct net *net, const char *name, unsigned int valid_hooks,
        struct xt_counters *counters;
        struct ipt_entry *iter;
 
-       ret = 0;
        counters = xt_counters_alloc(num_counters);
        if (!counters) {
                ret = -ENOMEM;
@@ -1090,7 +1089,7 @@ __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);
-       return ret;
+       return 0;
 
  put_module:
        module_put(t->me);
index a579ea14a69b67cdd641e1bf1dc943b8b8468007..7ba68388d2e1f5a7c83f850ed671be3355196770 100644 (file)
@@ -1062,7 +1062,6 @@ __do_replace(struct net *net, const char *name, unsigned int valid_hooks,
        struct xt_counters *counters;
        struct ip6t_entry *iter;
 
-       ret = 0;
        counters = xt_counters_alloc(num_counters);
        if (!counters) {
                ret = -ENOMEM;
@@ -1108,7 +1107,7 @@ __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);
-       return ret;
+       return 0;
 
  put_module:
        module_put(t->me);