Skip to content

Commit a37b85c

Browse files
Vlad Yasevichdavem330
authored andcommitted
bridge: Validate that vlan is permitted on ingress
When a frame arrives on a port or transmitted by the bridge, if we have VLANs configured, validate that a given VLAN is allowed to enter the bridge. Signed-off-by: Vlad Yasevich <vyasevic@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent 243a2e6 commit a37b85c

File tree

4 files changed

+85
-0
lines changed

4 files changed

+85
-0
lines changed

net/bridge/br_device.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@ netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev)
4545
brstats->tx_bytes += skb->len;
4646
u64_stats_update_end(&brstats->syncp);
4747

48+
if (!br_allowed_ingress(br, br_get_vlan_info(br), skb))
49+
goto out;
50+
4851
BR_INPUT_SKB_CB(skb)->brdev = dev;
4952

5053
skb_reset_mac_header(skb);

net/bridge/br_input.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include <linux/etherdevice.h>
1818
#include <linux/netfilter_bridge.h>
1919
#include <linux/export.h>
20+
#include <linux/rculist.h>
2021
#include "br_private.h"
2122

2223
/* Hook for brouter */
@@ -54,6 +55,9 @@ int br_handle_frame_finish(struct sk_buff *skb)
5455
if (!p || p->state == BR_STATE_DISABLED)
5556
goto drop;
5657

58+
if (!br_allowed_ingress(p->br, nbp_get_vlan_info(p), skb))
59+
goto drop;
60+
5761
/* insert into forwarding database after filtering to avoid spoofing */
5862
br = p->br;
5963
br_fdb_update(br, p, eth_hdr(skb)->h_source);

net/bridge/br_private.h

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -552,14 +552,52 @@ static inline void br_mdb_uninit(void)
552552

553553
/* br_vlan.c */
554554
#ifdef CONFIG_BRIDGE_VLAN_FILTERING
555+
extern bool br_allowed_ingress(struct net_bridge *br, struct net_port_vlans *v,
556+
struct sk_buff *skb);
555557
extern int br_vlan_add(struct net_bridge *br, u16 vid);
556558
extern int br_vlan_delete(struct net_bridge *br, u16 vid);
557559
extern void br_vlan_flush(struct net_bridge *br);
558560
extern int br_vlan_filter_toggle(struct net_bridge *br, unsigned long val);
559561
extern int nbp_vlan_add(struct net_bridge_port *port, u16 vid);
560562
extern int nbp_vlan_delete(struct net_bridge_port *port, u16 vid);
561563
extern void nbp_vlan_flush(struct net_bridge_port *port);
564+
565+
static inline struct net_port_vlans *br_get_vlan_info(
566+
const struct net_bridge *br)
567+
{
568+
return rcu_dereference(br->vlan_info);
569+
}
570+
571+
static inline struct net_port_vlans *nbp_get_vlan_info(
572+
const struct net_bridge_port *p)
573+
{
574+
return rcu_dereference(p->vlan_info);
575+
}
576+
577+
/* Since bridge now depends on 8021Q module, but the time bridge sees the
578+
* skb, the vlan tag will always be present if the frame was tagged.
579+
*/
580+
static inline int br_vlan_get_tag(const struct sk_buff *skb, u16 *vid)
581+
{
582+
int err = 0;
583+
584+
if (vlan_tx_tag_present(skb))
585+
*vid = vlan_tx_tag_get(skb) & VLAN_VID_MASK;
586+
else {
587+
*vid = 0;
588+
err = -EINVAL;
589+
}
590+
591+
return err;
592+
}
562593
#else
594+
static inline bool br_allowed_ingress(struct net_bridge *br,
595+
struct net_port_vlans *v,
596+
struct sk_buff *skb)
597+
{
598+
return true;
599+
}
600+
563601
static inline int br_vlan_add(struct net_bridge *br, u16 vid)
564602
{
565603
return -EOPNOTSUPP;
@@ -588,6 +626,21 @@ static inline void nbp_vlan_flush(struct net_bridge_port *port)
588626
{
589627
}
590628

629+
static inline struct net_port_vlans *br_get_vlan_info(
630+
const struct net_bridge *br)
631+
{
632+
return NULL;
633+
}
634+
static inline struct net_port_vlans *nbp_get_vlan_info(
635+
const struct net_bridge_port *p)
636+
{
637+
return NULL;
638+
}
639+
640+
static inline u16 br_vlan_get_tag(const struct sk_buff *skb)
641+
{
642+
return 0;
643+
}
591644
#endif
592645

593646
/* br_netfilter.c */

net/bridge/br_vlan.c

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,31 @@ static void __vlan_flush(struct net_port_vlans *v)
6464
kfree_rcu(v, rcu);
6565
}
6666

67+
/* Called under RCU */
68+
bool br_allowed_ingress(struct net_bridge *br, struct net_port_vlans *v,
69+
struct sk_buff *skb)
70+
{
71+
u16 vid;
72+
73+
/* If VLAN filtering is disabled on the bridge, all packets are
74+
* permitted.
75+
*/
76+
if (!br->vlan_enabled)
77+
return true;
78+
79+
/* If there are no vlan in the permitted list, all packets are
80+
* rejected.
81+
*/
82+
if (!v)
83+
return false;
84+
85+
br_vlan_get_tag(skb, &vid);
86+
if (test_bit(vid, v->vlan_bitmap))
87+
return true;
88+
89+
return false;
90+
}
91+
6792
/* Must be protected by RTNL */
6893
int br_vlan_add(struct net_bridge *br, u16 vid)
6994
{

0 commit comments

Comments
 (0)