Skip to content

Commit

Permalink
bridge: Fix crash with vlan filtering and tcpdump
Browse files Browse the repository at this point in the history
When the vlan filtering is enabled on the bridge, but
the filter is not configured on the bridge device itself,
running tcpdump on the bridge device will result in a
an Oops with NULL pointer dereference.  The reason
is that br_pass_frame_up() will bypass the vlan
check because promisc flag is set.  It will then try
to get the table pointer and process the packet based
on the table.  Since the table pointer is NULL, we oops.
Catch this special condition in br_handle_vlan().

Reported-by: Toshiaki Makita <makita.toshiaki@lab.ntt.co.jp>
CC: Toshiaki Makita <makita.toshiaki@lab.ntt.co.jp>
Signed-off-by: Vlad Yasevich <vyasevic@redhat.com>
Acked-by: Toshiaki Makita <makita.toshiaki@lab.ntt.co.jp>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Vlad Yasevich authored and David S. Miller committed Mar 28, 2014
1 parent 53d6471 commit fc92f74
Show file tree
Hide file tree
Showing 2 changed files with 20 additions and 5 deletions.
11 changes: 6 additions & 5 deletions net/bridge/br_input.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ static int br_pass_frame_up(struct sk_buff *skb)
struct net_device *indev, *brdev = BR_INPUT_SKB_CB(skb)->brdev;
struct net_bridge *br = netdev_priv(brdev);
struct pcpu_sw_netstats *brstats = this_cpu_ptr(br->stats);
struct net_port_vlans *pv;

u64_stats_update_begin(&brstats->syncp);
brstats->rx_packets++;
Expand All @@ -39,18 +40,18 @@ static int br_pass_frame_up(struct sk_buff *skb)
* packet is allowed except in promisc modue when someone
* may be running packet capture.
*/
pv = br_get_vlan_info(br);
if (!(brdev->flags & IFF_PROMISC) &&
!br_allowed_egress(br, br_get_vlan_info(br), skb)) {
!br_allowed_egress(br, pv, skb)) {
kfree_skb(skb);
return NET_RX_DROP;
}

skb = br_handle_vlan(br, br_get_vlan_info(br), skb);
if (!skb)
return NET_RX_DROP;

indev = skb->dev;
skb->dev = brdev;
skb = br_handle_vlan(br, pv, skb);
if (!skb)
return NET_RX_DROP;

return NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_IN, skb, indev, NULL,
netif_receive_skb);
Expand Down
14 changes: 14 additions & 0 deletions net/bridge/br_vlan.c
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,20 @@ struct sk_buff *br_handle_vlan(struct net_bridge *br,
if (!br->vlan_enabled)
goto out;

/* Vlan filter table must be configured at this point. The
* only exception is the bridge is set in promisc mode and the
* packet is destined for the bridge device. In this case
* pass the packet as is.
*/
if (!pv) {
if ((br->dev->flags & IFF_PROMISC) && skb->dev == br->dev) {
goto out;
} else {
kfree_skb(skb);
return NULL;
}
}

/* At this point, we know that the frame was filtered and contains
* a valid vlan id. If the vlan id is set in the untagged bitmap,
* send untagged; otherwise, send tagged.
Expand Down

0 comments on commit fc92f74

Please sign in to comment.