[Devel,vz7] bridge: drop netfilter fake rtable unconditionally

Submitted by Kirill Gorkunov on April 14, 2017, 12:29 p.m.

Details

Message ID 20170414122928.GA28138@uranus
State New
Series "bridge: drop netfilter fake rtable unconditionally"
Headers show

Commit Message

Kirill Gorkunov April 14, 2017, 12:29 p.m.
From: Florian Westphal <fw@strlen.de>

Andreas reports kernel oops during rmmod of the br_netfilter module.
Hannes debugged the oops down to a NULL rt6info->rt6i_indev.

Problem is that br_netfilter has the nasty concept of adding a fake
rtable to skb->dst; this happens in a br_netfilter prerouting hook.

A second hook (in bridge LOCAL_IN) is supposed to remove these again
before the skb is handed up the stack.

However, on module unload hooks get unregistered which means an
skb could traverse the prerouting hook that attaches the fake_rtable,
while the 'fake rtable remove' hook gets removed from the hooklist
immediately after.

Fixes: 34666d467cbf1e2e3c7 ("netfilter: bridge: move br_netfilter out of the core")
Reported-by: Andreas Karis <akaris@redhat.com>
Debugged-by: Hannes Frederic Sowa <hannes@stressinduktion.org>
Signed-off-by: Florian Westphal <fw@strlen.de>
Acked-by: Pablo Neira Ayuso <pablo@netfilter.org>
Signed-off-by: David S. Miller <davem@davemloft.net>

Backport of a13b2082ece95247779b9995c4e91b4246bed023
https://jira.sw.ru/browse/PSBM-64412

Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org>
---

Guys, take a look please, this should do the trick.

 net/bridge/br_input.c           |    2 ++
 net/bridge/br_netfilter.c       |   24 ------------------------
 net/bridge/br_netfilter_hooks.c |   24 ------------------------
 3 files changed, 2 insertions(+), 48 deletions(-)

Patch hide | download patch | download mbox

Index: linux-pcs7.git/net/bridge/br_input.c
===================================================================
--- linux-pcs7.git.orig/net/bridge/br_input.c
+++ linux-pcs7.git/net/bridge/br_input.c
@@ -53,6 +53,8 @@  static int br_pass_frame_up(struct sk_bu
 	if (!skb)
 		return NET_RX_DROP;
 
+	br_drop_fake_rtable(skb);
+
 	return NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_IN, NULL, skb,
 		       indev, NULL,
 		       netif_receive_skb_sk);
Index: linux-pcs7.git/net/bridge/br_netfilter.c
===================================================================
--- linux-pcs7.git.orig/net/bridge/br_netfilter.c
+++ linux-pcs7.git/net/bridge/br_netfilter.c
@@ -760,23 +760,6 @@  static unsigned int br_nf_pre_routing(co
 }
 
 
-/* PF_BRIDGE/LOCAL_IN ************************************************/
-/* The packet is locally destined, which requires a real
- * dst_entry, so detach the fake one.  On the way up, the
- * packet would pass through PRE_ROUTING again (which already
- * took place when the packet entered the bridge), but we
- * register an IPv4 PRE_ROUTING 'sabotage' hook that will
- * prevent this from happening. */
-static unsigned int br_nf_local_in(const struct nf_hook_ops *ops,
-				   struct sk_buff *skb,
-				   const struct net_device *in,
-				   const struct net_device *out,
-				   const struct nf_hook_state *state)
-{
-	br_drop_fake_rtable(skb);
-	return NF_ACCEPT;
-}
-
 /* PF_BRIDGE/FORWARD *************************************************/
 static int br_nf_forward_finish(struct sock *sk, struct sk_buff *skb)
 {
@@ -1027,13 +1010,6 @@  static struct nf_hook_ops br_nf_ops[] __
 		.priority = NF_BR_PRI_BRNF,
 	},
 	{
-		.hook = br_nf_local_in,
-		.owner = THIS_MODULE,
-		.pf = NFPROTO_BRIDGE,
-		.hooknum = NF_BR_LOCAL_IN,
-		.priority = NF_BR_PRI_BRNF,
-	},
-	{
 		.hook = br_nf_forward_ip,
 		.owner = THIS_MODULE,
 		.pf = NFPROTO_BRIDGE,
Index: linux-pcs7.git/net/bridge/br_netfilter_hooks.c
===================================================================
--- linux-pcs7.git.orig/net/bridge/br_netfilter_hooks.c
+++ linux-pcs7.git/net/bridge/br_netfilter_hooks.c
@@ -520,23 +520,6 @@  static unsigned int br_nf_pre_routing(co
 }
 
 
-/* PF_BRIDGE/LOCAL_IN ************************************************/
-/* The packet is locally destined, which requires a real
- * dst_entry, so detach the fake one.  On the way up, the
- * packet would pass through PRE_ROUTING again (which already
- * took place when the packet entered the bridge), but we
- * register an IPv4 PRE_ROUTING 'sabotage' hook that will
- * prevent this from happening. */
-static unsigned int br_nf_local_in(const struct nf_hook_ops *ops,
-				   struct sk_buff *skb,
-				   const struct net_device *in,
-				   const struct net_device *out,
-				   const struct nf_hook_state *state)
-{
-	br_drop_fake_rtable(skb);
-	return NF_ACCEPT;
-}
-
 /* PF_BRIDGE/FORWARD *************************************************/
 static int br_nf_forward_finish(struct sock *sk, struct sk_buff *skb)
 {
@@ -922,13 +905,6 @@  static struct nf_hook_ops br_nf_ops[] __
 		.priority = NF_BR_PRI_BRNF,
 	},
 	{
-		.hook = br_nf_local_in,
-		.owner = THIS_MODULE,
-		.pf = NFPROTO_BRIDGE,
-		.hooknum = NF_BR_LOCAL_IN,
-		.priority = NF_BR_PRI_BRNF,
-	},
-	{
 		.hook = br_nf_forward_ip,
 		.owner = THIS_MODULE,
 		.pf = NFPROTO_BRIDGE,