netfilter: br_netfilter: fix recent physdev match breakage
authorFlorian Westphal <fw@strlen.de>
Mon, 3 Apr 2023 11:54:37 +0000 (13:54 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 26 Apr 2023 12:28:32 +0000 (14:28 +0200)
[ Upstream commit 94623f579ce338b5fa61b5acaa5beb8aa657fb9e ]

Recent attempt to ensure PREROUTING hook is executed again when a
decrypted ipsec packet received on a bridge passes through the network
stack a second time broke the physdev match in INPUT hook.

We can't discard the nf_bridge info strct from sabotage_in hook, as
this is needed by the physdev match.

Keep the struct around and handle this with another conditional instead.

Fixes: 2b272bb558f1 ("netfilter: br_netfilter: disable sabotage_in hook after first suppression")
Reported-and-tested-by: Farid BENAMROUCHE <fariouche@yahoo.fr>
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>
include/linux/skbuff.h
net/bridge/br_netfilter_hooks.c

index 7be5bb4..a0d2715 100644 (file)
@@ -291,6 +291,7 @@ struct nf_bridge_info {
        u8                      pkt_otherhost:1;
        u8                      in_prerouting:1;
        u8                      bridged_dnat:1;
+       u8                      sabotage_in_done:1;
        __u16                   frag_max_size;
        struct net_device       *physindev;
 
index 9554abc..812bd7e 100644 (file)
@@ -868,12 +868,17 @@ static unsigned int ip_sabotage_in(void *priv,
 {
        struct nf_bridge_info *nf_bridge = nf_bridge_info_get(skb);
 
-       if (nf_bridge && !nf_bridge->in_prerouting &&
-           !netif_is_l3_master(skb->dev) &&
-           !netif_is_l3_slave(skb->dev)) {
-               nf_bridge_info_free(skb);
-               state->okfn(state->net, state->sk, skb);
-               return NF_STOLEN;
+       if (nf_bridge) {
+               if (nf_bridge->sabotage_in_done)
+                       return NF_ACCEPT;
+
+               if (!nf_bridge->in_prerouting &&
+                   !netif_is_l3_master(skb->dev) &&
+                   !netif_is_l3_slave(skb->dev)) {
+                       nf_bridge->sabotage_in_done = 1;
+                       state->okfn(state->net, state->sk, skb);
+                       return NF_STOLEN;
+               }
        }
 
        return NF_ACCEPT;