Skip to content

Commit 751de20

Browse files
committed
netfilter: br_netfilter: skip conntrack input hook for promisc packets
For historical reasons, when bridge device is in promisc mode, packets that are directed to the taps follow bridge input hook path. This patch adds a workaround to reset conntrack for these packets. Jianbo Liu reports warning splats in their test infrastructure where cloned packets reach the br_netfilter input hook to confirm the conntrack object. Scratch one bit from BR_INPUT_SKB_CB to annotate that this packet has reached the input hook because it is passed up to the bridge device to reach the taps. [ 57.571874] WARNING: CPU: 1 PID: 0 at net/bridge/br_netfilter_hooks.c:616 br_nf_local_in+0x157/0x180 [br_netfilter] [ 57.572749] Modules linked in: xt_MASQUERADE nf_conntrack_netlink nfnetlink iptable_nat xt_addrtype xt_conntrack nf_nat br_netfilter rpcsec_gss_krb5 auth_rpcgss oid_registry overlay rpcrdma rdma_ucm ib_iser libiscsi scsi_transport_isc si ib_umad rdma_cm ib_ipoib iw_cm ib_cm mlx5_ib ib_uverbs ib_core mlx5ctl mlx5_core [ 57.575158] CPU: 1 PID: 0 Comm: swapper/1 Not tainted 6.8.0+ #19 [ 57.575700] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.13.0-0-gf21b5a4aeb02-prebuilt.qemu.org 04/01/2014 [ 57.576662] RIP: 0010:br_nf_local_in+0x157/0x180 [br_netfilter] [ 57.577195] Code: fe ff ff 41 bd 04 00 00 00 be 04 00 00 00 e9 4a ff ff ff be 04 00 00 00 48 89 ef e8 f3 a9 3c e1 66 83 ad b4 00 00 00 04 eb 91 <0f> 0b e9 f1 fe ff ff 0f 0b e9 df fe ff ff 48 89 df e8 b3 53 47 e1 [ 57.578722] RSP: 0018:ffff88885f845a08 EFLAGS: 00010202 [ 57.579207] RAX: 0000000000000002 RBX: ffff88812dfe8000 RCX: 0000000000000000 [ 57.579830] RDX: ffff88885f845a60 RSI: ffff8881022dc300 RDI: 0000000000000000 [ 57.580454] RBP: ffff88885f845a60 R08: 0000000000000001 R09: 0000000000000003 [ 57.581076] R10: 00000000ffff1300 R11: 0000000000000002 R12: 0000000000000000 [ 57.581695] R13: ffff8881047ffe00 R14: ffff888108dbee00 R15: ffff88814519b800 [ 57.582313] FS: 0000000000000000(0000) GS:ffff88885f840000(0000) knlGS:0000000000000000 [ 57.583040] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 57.583564] CR2: 000000c4206aa000 CR3: 0000000103847001 CR4: 0000000000370eb0 [ 57.584194] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 [ 57.584820] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 [ 57.585440] Call Trace: [ 57.585721] <IRQ> [ 57.585976] ? __warn+0x7d/0x130 [ 57.586323] ? br_nf_local_in+0x157/0x180 [br_netfilter] [ 57.586811] ? report_bug+0xf1/0x1c0 [ 57.587177] ? handle_bug+0x3f/0x70 [ 57.587539] ? exc_invalid_op+0x13/0x60 [ 57.587929] ? asm_exc_invalid_op+0x16/0x20 [ 57.588336] ? br_nf_local_in+0x157/0x180 [br_netfilter] [ 57.588825] nf_hook_slow+0x3d/0xd0 [ 57.589188] ? br_handle_vlan+0x4b/0x110 [ 57.589579] br_pass_frame_up+0xfc/0x150 [ 57.589970] ? br_port_flags_change+0x40/0x40 [ 57.590396] br_handle_frame_finish+0x346/0x5e0 [ 57.590837] ? ipt_do_table+0x32e/0x430 [ 57.591221] ? br_handle_local_finish+0x20/0x20 [ 57.591656] br_nf_hook_thresh+0x4b/0xf0 [br_netfilter] [ 57.592286] ? br_handle_local_finish+0x20/0x20 [ 57.592802] br_nf_pre_routing_finish+0x178/0x480 [br_netfilter] [ 57.593348] ? br_handle_local_finish+0x20/0x20 [ 57.593782] ? nf_nat_ipv4_pre_routing+0x25/0x60 [nf_nat] [ 57.594279] br_nf_pre_routing+0x24c/0x550 [br_netfilter] [ 57.594780] ? br_nf_hook_thresh+0xf0/0xf0 [br_netfilter] [ 57.595280] br_handle_frame+0x1f3/0x3d0 [ 57.595676] ? br_handle_local_finish+0x20/0x20 [ 57.596118] ? br_handle_frame_finish+0x5e0/0x5e0 [ 57.596566] __netif_receive_skb_core+0x25b/0xfc0 [ 57.597017] ? __napi_build_skb+0x37/0x40 [ 57.597418] __netif_receive_skb_list_core+0xfb/0x220 Fixes: 62e7151 ("netfilter: bridge: confirm multicast packets before passing them up the stack") Reported-by: Jianbo Liu <[email protected]> Signed-off-by: Pablo Neira Ayuso <[email protected]>
1 parent d78d867 commit 751de20

File tree

4 files changed

+28
-8
lines changed

4 files changed

+28
-8
lines changed

net/bridge/br_input.c

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ br_netif_receive_skb(struct net *net, struct sock *sk, struct sk_buff *skb)
3030
return netif_receive_skb(skb);
3131
}
3232

33-
static int br_pass_frame_up(struct sk_buff *skb)
33+
static int br_pass_frame_up(struct sk_buff *skb, bool promisc)
3434
{
3535
struct net_device *indev, *brdev = BR_INPUT_SKB_CB(skb)->brdev;
3636
struct net_bridge *br = netdev_priv(brdev);
@@ -65,6 +65,8 @@ static int br_pass_frame_up(struct sk_buff *skb)
6565
br_multicast_count(br, NULL, skb, br_multicast_igmp_type(skb),
6666
BR_MCAST_DIR_TX);
6767

68+
BR_INPUT_SKB_CB(skb)->promisc = promisc;
69+
6870
return NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_IN,
6971
dev_net(indev), NULL, skb, indev, NULL,
7072
br_netif_receive_skb);
@@ -82,6 +84,7 @@ int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb
8284
struct net_bridge_mcast *brmctx;
8385
struct net_bridge_vlan *vlan;
8486
struct net_bridge *br;
87+
bool promisc;
8588
u16 vid = 0;
8689
u8 state;
8790

@@ -137,7 +140,9 @@ int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb
137140
if (p->flags & BR_LEARNING)
138141
br_fdb_update(br, p, eth_hdr(skb)->h_source, vid, 0);
139142

140-
local_rcv = !!(br->dev->flags & IFF_PROMISC);
143+
promisc = !!(br->dev->flags & IFF_PROMISC);
144+
local_rcv = promisc;
145+
141146
if (is_multicast_ether_addr(eth_hdr(skb)->h_dest)) {
142147
/* by definition the broadcast is also a multicast address */
143148
if (is_broadcast_ether_addr(eth_hdr(skb)->h_dest)) {
@@ -200,7 +205,7 @@ int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb
200205
unsigned long now = jiffies;
201206

202207
if (test_bit(BR_FDB_LOCAL, &dst->flags))
203-
return br_pass_frame_up(skb);
208+
return br_pass_frame_up(skb, false);
204209

205210
if (now != dst->used)
206211
dst->used = now;
@@ -213,7 +218,7 @@ int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb
213218
}
214219

215220
if (local_rcv)
216-
return br_pass_frame_up(skb);
221+
return br_pass_frame_up(skb, promisc);
217222

218223
out:
219224
return 0;
@@ -386,6 +391,8 @@ static rx_handler_result_t br_handle_frame(struct sk_buff **pskb)
386391
goto forward;
387392
}
388393

394+
BR_INPUT_SKB_CB(skb)->promisc = false;
395+
389396
/* The else clause should be hit when nf_hook():
390397
* - returns < 0 (drop/error)
391398
* - returns = 0 (stolen/nf_queue)

net/bridge/br_netfilter_hooks.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -600,11 +600,17 @@ static unsigned int br_nf_local_in(void *priv,
600600
struct sk_buff *skb,
601601
const struct nf_hook_state *state)
602602
{
603+
bool promisc = BR_INPUT_SKB_CB(skb)->promisc;
603604
struct nf_conntrack *nfct = skb_nfct(skb);
604605
const struct nf_ct_hook *ct_hook;
605606
struct nf_conn *ct;
606607
int ret;
607608

609+
if (promisc) {
610+
nf_reset_ct(skb);
611+
return NF_ACCEPT;
612+
}
613+
608614
if (!nfct || skb->pkt_type == PACKET_HOST)
609615
return NF_ACCEPT;
610616

net/bridge/br_private.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -589,6 +589,7 @@ struct br_input_skb_cb {
589589
#endif
590590
u8 proxyarp_replied:1;
591591
u8 src_port_isolated:1;
592+
u8 promisc:1;
592593
#ifdef CONFIG_BRIDGE_VLAN_FILTERING
593594
u8 vlan_filtered:1;
594595
#endif

net/bridge/netfilter/nf_conntrack_bridge.c

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -294,18 +294,24 @@ static unsigned int nf_ct_bridge_pre(void *priv, struct sk_buff *skb,
294294
static unsigned int nf_ct_bridge_in(void *priv, struct sk_buff *skb,
295295
const struct nf_hook_state *state)
296296
{
297-
enum ip_conntrack_info ctinfo;
297+
bool promisc = BR_INPUT_SKB_CB(skb)->promisc;
298+
struct nf_conntrack *nfct = skb_nfct(skb);
298299
struct nf_conn *ct;
299300

300-
if (skb->pkt_type == PACKET_HOST)
301+
if (promisc) {
302+
nf_reset_ct(skb);
303+
return NF_ACCEPT;
304+
}
305+
306+
if (!nfct || skb->pkt_type == PACKET_HOST)
301307
return NF_ACCEPT;
302308

303309
/* nf_conntrack_confirm() cannot handle concurrent clones,
304310
* this happens for broad/multicast frames with e.g. macvlan on top
305311
* of the bridge device.
306312
*/
307-
ct = nf_ct_get(skb, &ctinfo);
308-
if (!ct || nf_ct_is_confirmed(ct) || nf_ct_is_template(ct))
313+
ct = container_of(nfct, struct nf_conn, ct_general);
314+
if (nf_ct_is_confirmed(ct) || nf_ct_is_template(ct))
309315
return NF_ACCEPT;
310316

311317
/* let inet prerouting call conntrack again */

0 commit comments

Comments
 (0)