diff mbox series

[net,01/14] netfilter: ebtables: reject blobs that don't provide all entry points

Message ID 20220824220330.64283-2-pablo@netfilter.org
State Accepted
Delegated to: Pablo Neira
Headers show
Series [net,01/14] netfilter: ebtables: reject blobs that don't provide all entry points | expand

Commit Message

Pablo Neira Ayuso Aug. 24, 2022, 10:03 p.m. UTC
From: Florian Westphal <fw@strlen.de>

Harshit Mogalapalli says:
 In ebt_do_table() function dereferencing 'private->hook_entry[hook]'
 can lead to NULL pointer dereference. [..] Kernel panic:

general protection fault, probably for non-canonical address 0xdffffc0000000005: 0000 [#1] PREEMPT SMP KASAN
KASAN: null-ptr-deref in range [0x0000000000000028-0x000000000000002f]
[..]
RIP: 0010:ebt_do_table+0x1dc/0x1ce0
Code: 89 fa 48 c1 ea 03 80 3c 02 00 0f 85 5c 16 00 00 48 b8 00 00 00 00 00 fc ff df 49 8b 6c df 08 48 8d 7d 2c 48 89 fa 48 c1 ea 03 <0f> b6 14 02 48 89 f8 83 e0 07 83 c0 03 38 d0 7c 08 84 d2 0f 85 88
[..]
Call Trace:
 nf_hook_slow+0xb1/0x170
 __br_forward+0x289/0x730
 maybe_deliver+0x24b/0x380
 br_flood+0xc6/0x390
 br_dev_xmit+0xa2e/0x12c0

For some reason ebtables rejects blobs that provide entry points that are
not supported by the table, but what it should instead reject is the
opposite: blobs that DO NOT provide an entry point supported by the table.

t->valid_hooks is the bitmask of hooks (input, forward ...) that will see
packets.  Providing an entry point that is not support is harmless
(never called/used), but the inverse isn't: it results in a crash
because the ebtables traverser doesn't expect a NULL blob for a location
its receiving packets for.

Instead of fixing all the individual checks, do what iptables is doing and
reject all blobs that differ from the expected hooks.

Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Reported-by: Harshit Mogalapalli <harshit.m.mogalapalli@oracle.com>
Reported-by: syzkaller <syzkaller@googlegroups.com>
Signed-off-by: Florian Westphal <fw@strlen.de>
---
 include/linux/netfilter_bridge/ebtables.h | 4 ----
 net/bridge/netfilter/ebtable_broute.c     | 8 --------
 net/bridge/netfilter/ebtable_filter.c     | 8 --------
 net/bridge/netfilter/ebtable_nat.c        | 8 --------
 net/bridge/netfilter/ebtables.c           | 8 +-------
 5 files changed, 1 insertion(+), 35 deletions(-)

Comments

patchwork-bot+netdevbpf@kernel.org Aug. 25, 2022, 2:40 a.m. UTC | #1
Hello:

This series was applied to netdev/net.git (master)
by Pablo Neira Ayuso <pablo@netfilter.org>:

On Thu, 25 Aug 2022 00:03:17 +0200 you wrote:
> From: Florian Westphal <fw@strlen.de>
> 
> Harshit Mogalapalli says:
>  In ebt_do_table() function dereferencing 'private->hook_entry[hook]'
>  can lead to NULL pointer dereference. [..] Kernel panic:
> 
> general protection fault, probably for non-canonical address 0xdffffc0000000005: 0000 [#1] PREEMPT SMP KASAN
> KASAN: null-ptr-deref in range [0x0000000000000028-0x000000000000002f]
> [..]
> RIP: 0010:ebt_do_table+0x1dc/0x1ce0
> Code: 89 fa 48 c1 ea 03 80 3c 02 00 0f 85 5c 16 00 00 48 b8 00 00 00 00 00 fc ff df 49 8b 6c df 08 48 8d 7d 2c 48 89 fa 48 c1 ea 03 <0f> b6 14 02 48 89 f8 83 e0 07 83 c0 03 38 d0 7c 08 84 d2 0f 85 88
> [..]
> Call Trace:
>  nf_hook_slow+0xb1/0x170
>  __br_forward+0x289/0x730
>  maybe_deliver+0x24b/0x380
>  br_flood+0xc6/0x390
>  br_dev_xmit+0xa2e/0x12c0
> 
> [...]

Here is the summary with links:
  - [net,01/14] netfilter: ebtables: reject blobs that don't provide all entry points
    https://git.kernel.org/netdev/net/c/7997eff82828
  - [net,02/14] netfilter: conntrack: work around exceeded receive window
    https://git.kernel.org/netdev/net/c/cf97769c761a
  - [net,03/14] netfilter: nft_tproxy: restrict to prerouting hook
    https://git.kernel.org/netdev/net/c/18bbc3213383
  - [net,04/14] netfilter: nf_tables: disallow updates of implicit chain
    https://git.kernel.org/netdev/net/c/5dc52d83baac
  - [net,05/14] netfilter: nf_tables: make table handle allocation per-netns friendly
    https://git.kernel.org/netdev/net/c/ab482c6b66a4
  - [net,06/14] netfilter: nft_payload: report ERANGE for too long offset and length
    https://git.kernel.org/netdev/net/c/94254f990c07
  - [net,07/14] netfilter: nft_payload: do not truncate csum_offset and csum_type
    https://git.kernel.org/netdev/net/c/7044ab281feb
  - [net,08/14] netfilter: nf_tables: do not leave chain stats enabled on error
    https://git.kernel.org/netdev/net/c/43eb8949cfdf
  - [net,09/14] netfilter: nft_osf: restrict osf to ipv4, ipv6 and inet families
    https://git.kernel.org/netdev/net/c/5f3b7aae14a7
  - [net,10/14] netfilter: nft_tunnel: restrict it to netdev family
    https://git.kernel.org/netdev/net/c/01e4092d53bc
  - [net,11/14] netfilter: nf_tables: disallow binding to already bound chain
    https://git.kernel.org/netdev/net/c/e02f0d397040
  - [net,12/14] netfilter: flowtable: add function to invoke garbage collection immediately
    https://git.kernel.org/netdev/net/c/759eebbcfafc
  - [net,13/14] netfilter: flowtable: fix stuck flows on cleanup due to pending work
    https://git.kernel.org/netdev/net/c/9afb4b27349a
  - [net,14/14] netfilter: nf_defrag_ipv6: allow nf_conntrack_frag6_high_thresh increases
    https://git.kernel.org/netdev/net/c/00cd7bf9f9e0

You are awesome, thank you!
diff mbox series

Patch

diff --git a/include/linux/netfilter_bridge/ebtables.h b/include/linux/netfilter_bridge/ebtables.h
index a13296d6c7ce..fd533552a062 100644
--- a/include/linux/netfilter_bridge/ebtables.h
+++ b/include/linux/netfilter_bridge/ebtables.h
@@ -94,10 +94,6 @@  struct ebt_table {
 	struct ebt_replace_kernel *table;
 	unsigned int valid_hooks;
 	rwlock_t lock;
-	/* e.g. could be the table explicitly only allows certain
-	 * matches, targets, ... 0 == let it in */
-	int (*check)(const struct ebt_table_info *info,
-	   unsigned int valid_hooks);
 	/* the data used by the kernel */
 	struct ebt_table_info *private;
 	struct nf_hook_ops *ops;
diff --git a/net/bridge/netfilter/ebtable_broute.c b/net/bridge/netfilter/ebtable_broute.c
index 1a11064f9990..8f19253024b0 100644
--- a/net/bridge/netfilter/ebtable_broute.c
+++ b/net/bridge/netfilter/ebtable_broute.c
@@ -36,18 +36,10 @@  static struct ebt_replace_kernel initial_table = {
 	.entries	= (char *)&initial_chain,
 };
 
-static int check(const struct ebt_table_info *info, unsigned int valid_hooks)
-{
-	if (valid_hooks & ~(1 << NF_BR_BROUTING))
-		return -EINVAL;
-	return 0;
-}
-
 static const struct ebt_table broute_table = {
 	.name		= "broute",
 	.table		= &initial_table,
 	.valid_hooks	= 1 << NF_BR_BROUTING,
-	.check		= check,
 	.me		= THIS_MODULE,
 };
 
diff --git a/net/bridge/netfilter/ebtable_filter.c b/net/bridge/netfilter/ebtable_filter.c
index cb949436bc0e..278f324e6752 100644
--- a/net/bridge/netfilter/ebtable_filter.c
+++ b/net/bridge/netfilter/ebtable_filter.c
@@ -43,18 +43,10 @@  static struct ebt_replace_kernel initial_table = {
 	.entries	= (char *)initial_chains,
 };
 
-static int check(const struct ebt_table_info *info, unsigned int valid_hooks)
-{
-	if (valid_hooks & ~FILTER_VALID_HOOKS)
-		return -EINVAL;
-	return 0;
-}
-
 static const struct ebt_table frame_filter = {
 	.name		= "filter",
 	.table		= &initial_table,
 	.valid_hooks	= FILTER_VALID_HOOKS,
-	.check		= check,
 	.me		= THIS_MODULE,
 };
 
diff --git a/net/bridge/netfilter/ebtable_nat.c b/net/bridge/netfilter/ebtable_nat.c
index 5ee0531ae506..9066f7f376d5 100644
--- a/net/bridge/netfilter/ebtable_nat.c
+++ b/net/bridge/netfilter/ebtable_nat.c
@@ -43,18 +43,10 @@  static struct ebt_replace_kernel initial_table = {
 	.entries	= (char *)initial_chains,
 };
 
-static int check(const struct ebt_table_info *info, unsigned int valid_hooks)
-{
-	if (valid_hooks & ~NAT_VALID_HOOKS)
-		return -EINVAL;
-	return 0;
-}
-
 static const struct ebt_table frame_nat = {
 	.name		= "nat",
 	.table		= &initial_table,
 	.valid_hooks	= NAT_VALID_HOOKS,
-	.check		= check,
 	.me		= THIS_MODULE,
 };
 
diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c
index f2dbefb61ce8..9a0ae59cdc50 100644
--- a/net/bridge/netfilter/ebtables.c
+++ b/net/bridge/netfilter/ebtables.c
@@ -1040,8 +1040,7 @@  static int do_replace_finish(struct net *net, struct ebt_replace *repl,
 		goto free_iterate;
 	}
 
-	/* the table doesn't like it */
-	if (t->check && (ret = t->check(newinfo, repl->valid_hooks)))
+	if (repl->valid_hooks != t->valid_hooks)
 		goto free_unlock;
 
 	if (repl->num_counters && repl->num_counters != t->private->nentries) {
@@ -1231,11 +1230,6 @@  int ebt_register_table(struct net *net, const struct ebt_table *input_table,
 	if (ret != 0)
 		goto free_chainstack;
 
-	if (table->check && table->check(newinfo, table->valid_hooks)) {
-		ret = -EINVAL;
-		goto free_chainstack;
-	}
-
 	table->private = newinfo;
 	rwlock_init(&table->lock);
 	mutex_lock(&ebt_mutex);