Skip to content

Commit 48cc32d

Browse files
Florian Zumbiehldavem330
authored andcommitted
vlan: don't deliver frames for unknown vlans to protocols
6a32e4f made the vlan code skip marking vlan-tagged frames for not locally configured vlans as PACKET_OTHERHOST if there was an rx_handler, as the rx_handler could cause the frame to be received on a different (virtual) vlan-capable interface where that vlan might be configured. As rx_handlers do not necessarily return RX_HANDLER_ANOTHER, this could cause frames for unknown vlans to be delivered to the protocol stack as if they had been received untagged. For example, if an ipv6 router advertisement that's tagged for a locally not configured vlan is received on an interface with macvlan interfaces attached, macvlan's rx_handler returns RX_HANDLER_PASS after delivering the frame to the macvlan interfaces, which caused it to be passed to the protocol stack, leading to ipv6 addresses for the announced prefix being configured even though those are completely unusable on the underlying interface. The fix moves marking as PACKET_OTHERHOST after the rx_handler so the rx_handler, if there is one, sees the frame unchanged, but afterwards, before the frame is delivered to the protocol stack, it gets marked whether there is an rx_handler or not. Signed-off-by: Florian Zumbiehl <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 2e71a6f commit 48cc32d

File tree

3 files changed

+11
-14
lines changed

3 files changed

+11
-14
lines changed

include/linux/if_vlan.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,8 @@ static inline int is_vlan_dev(struct net_device *dev)
8080
}
8181

8282
#define vlan_tx_tag_present(__skb) ((__skb)->vlan_tci & VLAN_TAG_PRESENT)
83+
#define vlan_tx_nonzero_tag_present(__skb) \
84+
(vlan_tx_tag_present(__skb) && ((__skb)->vlan_tci & VLAN_VID_MASK))
8385
#define vlan_tx_tag_get(__skb) ((__skb)->vlan_tci & ~VLAN_TAG_PRESENT)
8486

8587
#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
@@ -89,7 +91,7 @@ extern struct net_device *__vlan_find_dev_deep(struct net_device *real_dev,
8991
extern struct net_device *vlan_dev_real_dev(const struct net_device *dev);
9092
extern u16 vlan_dev_vlan_id(const struct net_device *dev);
9193

92-
extern bool vlan_do_receive(struct sk_buff **skb, bool last_handler);
94+
extern bool vlan_do_receive(struct sk_buff **skb);
9395
extern struct sk_buff *vlan_untag(struct sk_buff *skb);
9496

9597
extern int vlan_vid_add(struct net_device *dev, unsigned short vid);
@@ -120,10 +122,8 @@ static inline u16 vlan_dev_vlan_id(const struct net_device *dev)
120122
return 0;
121123
}
122124

123-
static inline bool vlan_do_receive(struct sk_buff **skb, bool last_handler)
125+
static inline bool vlan_do_receive(struct sk_buff **skb)
124126
{
125-
if (((*skb)->vlan_tci & VLAN_VID_MASK) && last_handler)
126-
(*skb)->pkt_type = PACKET_OTHERHOST;
127127
return false;
128128
}
129129

net/8021q/vlan_core.c

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,22 +5,16 @@
55
#include <linux/export.h>
66
#include "vlan.h"
77

8-
bool vlan_do_receive(struct sk_buff **skbp, bool last_handler)
8+
bool vlan_do_receive(struct sk_buff **skbp)
99
{
1010
struct sk_buff *skb = *skbp;
1111
u16 vlan_id = skb->vlan_tci & VLAN_VID_MASK;
1212
struct net_device *vlan_dev;
1313
struct vlan_pcpu_stats *rx_stats;
1414

1515
vlan_dev = vlan_find_dev(skb->dev, vlan_id);
16-
if (!vlan_dev) {
17-
/* Only the last call to vlan_do_receive() should change
18-
* pkt_type to PACKET_OTHERHOST
19-
*/
20-
if (vlan_id && last_handler)
21-
skb->pkt_type = PACKET_OTHERHOST;
16+
if (!vlan_dev)
2217
return false;
23-
}
2418

2519
skb = *skbp = skb_share_check(skb, GFP_ATOMIC);
2620
if (unlikely(!skb))

net/core/dev.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3300,18 +3300,18 @@ static int __netif_receive_skb(struct sk_buff *skb)
33003300
&& !skb_pfmemalloc_protocol(skb))
33013301
goto drop;
33023302

3303-
rx_handler = rcu_dereference(skb->dev->rx_handler);
33043303
if (vlan_tx_tag_present(skb)) {
33053304
if (pt_prev) {
33063305
ret = deliver_skb(skb, pt_prev, orig_dev);
33073306
pt_prev = NULL;
33083307
}
3309-
if (vlan_do_receive(&skb, !rx_handler))
3308+
if (vlan_do_receive(&skb))
33103309
goto another_round;
33113310
else if (unlikely(!skb))
33123311
goto unlock;
33133312
}
33143313

3314+
rx_handler = rcu_dereference(skb->dev->rx_handler);
33153315
if (rx_handler) {
33163316
if (pt_prev) {
33173317
ret = deliver_skb(skb, pt_prev, orig_dev);
@@ -3331,6 +3331,9 @@ static int __netif_receive_skb(struct sk_buff *skb)
33313331
}
33323332
}
33333333

3334+
if (vlan_tx_nonzero_tag_present(skb))
3335+
skb->pkt_type = PACKET_OTHERHOST;
3336+
33343337
/* deliver only exact match when indicated */
33353338
null_or_dev = deliver_exact ? skb->dev : NULL;
33363339

0 commit comments

Comments
 (0)