[PATCH nf] netfilter: nft_fib: bail out if input device is missing

"Xiang Mei (Microsoft)" <[email protected]>
Newsgroups gmane.comp.security.firewalls.netfilter.devel,gmane.linux.network,gmane.linux.kernel
Message-ID <[email protected]>
nft_fib_can_skip() dereferences the input device (indev->ifindex, and
in->flags via nft_fib_is_loopback()) without a NULL check, assuming the
hook switch only admits PRE_ROUTING/INGRESS/LOCAL_IN. But NF_NETDEV_EGRESS
== NF_INET_LOCAL_IN == 1, so a netdev-family base chain on the egress hook
passes both the switch and nft_fib_validate() (which also keys only on the
hook number). Egress packets have no input device, so nft_fib_can_skip()
dereferences NULL.

  KASAN: null-ptr-deref in range [0x00000000000000b0-0x00000000000000b7]
  RIP: 0010:nft_fib4_eval (net/netfilter/nft_fib.h:19)
   nft_do_chain (net/netfilter/nf_tables_core.c:285)
   nft_do_chain_netdev (net/netfilter/nft_chain_filter.c:307)
   nf_hook_slow (net/netfilter/core.c:619)
   __dev_queue_xmit (net/core/dev.c:4799)
   ...
  Kernel panic - not syncing: Fatal exception in interrupt

The eval path touched the device only via l3mdev_master_ifindex_rcu(),
which tolerates NULL, until
commit eaaff9b6702e ("netfilter: fib: avoid lookup if socket is available")
added the sk/indev dereference. Restore the old behaviour by returning
early when indev is NULL, so the packet takes the regular FIB lookup.
Receive-side hooks always have an input device and are unaffected.

Fixes: eaaff9b6702e ("netfilter: fib: avoid lookup if socket is available")
Reported-by: [email protected]
Signed-off-by: Xiang Mei (Microsoft) <[email protected]>
---
 include/net/netfilter/nft_fib.h | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/include/net/netfilter/nft_fib.h b/include/net/netfilter/nft_fib.h
index e0422456f27b..d53e5a5214fe 100644
--- a/include/net/netfilter/nft_fib.h
+++ b/include/net/netfilter/nft_fib.h
@@ -33,6 +33,9 @@ static inline bool nft_fib_can_skip(const struct nft_pktinfo *pkt)
 		return false;
 	}
 
+	if (!indev)
+		return false;
+
 	sk = pkt->skb->sk;
 	if (sk && sk_fullsock(sk))
 	       return sk->sk_rx_dst_ifindex == indev->ifindex;
-- 
2.43.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.