Skip to content

Commit

Permalink
bridge: Fix incorrect re-injection of STP packets
Browse files Browse the repository at this point in the history
Commit 8626c56 ("bridge: fix potential use-after-free when hook
returns QUEUE or STOLEN verdict") fixed incorrect usage of NF_HOOK's
return value by consuming packets in okfn via br_pass_frame_up().

However, this function re-injects packets to the Rx path with skb->dev
set to the bridge device, which breaks kernel's STP, as all STP packets
appear to originate from the bridge device itself.

Instead, if STP is enabled and bridge isn't a 802.1ad bridge, then learn
packet's SMAC and inject it back to the Rx path for further processing
by the packet handlers.

The patch also makes netfilter's behavior consistent with regards to
packets destined to the Bridge Group Address, as no hook registered at
LOCAL_IN will ever be called, regardless if STP is enabled or not.

Cc: Florian Westphal <[email protected]>
Cc: Shmulik Ladkani <[email protected]>
Cc: Toshiaki Makita <[email protected]>
Fixes: 8626c56 ("bridge: fix potential use-after-free when hook returns QUEUE or STOLEN verdict")
Signed-off-by: Jiri Pirko <[email protected]>
Signed-off-by: Ido Schimmel <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
  • Loading branch information
idosch authored and davem330 committed Jun 11, 2016
1 parent fc0f7e3 commit 56fae40
Showing 1 changed file with 12 additions and 3 deletions.
15 changes: 12 additions & 3 deletions net/bridge/br_input.c
Original file line number Diff line number Diff line change
Expand Up @@ -213,15 +213,22 @@ int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb
}
EXPORT_SYMBOL_GPL(br_handle_frame_finish);

/* note: already called with rcu_read_lock */
static int br_handle_local_finish(struct net *net, struct sock *sk, struct sk_buff *skb)
static void __br_handle_local_finish(struct sk_buff *skb)
{
struct net_bridge_port *p = br_port_get_rcu(skb->dev);
u16 vid = 0;

/* check if vlan is allowed, to avoid spoofing */
if (p->flags & BR_LEARNING && br_should_learn(p, skb, &vid))
br_fdb_update(p->br, p, eth_hdr(skb)->h_source, vid, false);
}

/* note: already called with rcu_read_lock */
static int br_handle_local_finish(struct net *net, struct sock *sk, struct sk_buff *skb)
{
struct net_bridge_port *p = br_port_get_rcu(skb->dev);

__br_handle_local_finish(skb);

BR_INPUT_SKB_CB(skb)->brdev = p->br->dev;
br_pass_frame_up(skb);
Expand Down Expand Up @@ -274,7 +281,9 @@ rx_handler_result_t br_handle_frame(struct sk_buff **pskb)
if (p->br->stp_enabled == BR_NO_STP ||
fwd_mask & (1u << dest[5]))
goto forward;
break;
*pskb = skb;
__br_handle_local_finish(skb);
return RX_HANDLER_PASS;

case 0x01: /* IEEE MAC (Pause) */
goto drop;
Expand Down

0 comments on commit 56fae40

Please sign in to comment.