Skip to content

Commit 4179cb5

Browse files
Eric Dumazetdavem330
Eric Dumazet
authored andcommitted
vxlan: test dev->flags & IFF_UP before calling netif_rx()
netif_rx() must be called under a strict contract. At device dismantle phase, core networking clears IFF_UP and flush_all_backlogs() is called after rcu grace period to make sure no incoming packet might be in a cpu backlog and still referencing the device. Most drivers call netif_rx() from their interrupt handler, and since the interrupts are disabled at device dismantle, netif_rx() does not have to check dev->flags & IFF_UP Virtual drivers do not have this guarantee, and must therefore make the check themselves. Otherwise we risk use-after-free and/or crashes. Note this patch also fixes a small issue that came with commit ce6502a ("vxlan: fix a use after free in vxlan_encap_bypass"), since the dev->stats.rx_dropped change was done on the wrong device. Fixes: d342894 ("vxlan: virtual extensible lan") Fixes: ce6502a ("vxlan: fix a use after free in vxlan_encap_bypass") Signed-off-by: Eric Dumazet <[email protected]> Cc: Petr Machata <[email protected]> Cc: Ido Schimmel <[email protected]> Cc: Roopa Prabhu <[email protected]> Cc: Stefano Brivio <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 989723b commit 4179cb5

File tree

1 file changed

+11
-3
lines changed

1 file changed

+11
-3
lines changed

drivers/net/vxlan.c

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2219,7 +2219,7 @@ static void vxlan_encap_bypass(struct sk_buff *skb, struct vxlan_dev *src_vxlan,
22192219
struct pcpu_sw_netstats *tx_stats, *rx_stats;
22202220
union vxlan_addr loopback;
22212221
union vxlan_addr *remote_ip = &dst_vxlan->default_dst.remote_ip;
2222-
struct net_device *dev = skb->dev;
2222+
struct net_device *dev;
22232223
int len = skb->len;
22242224

22252225
tx_stats = this_cpu_ptr(src_vxlan->dev->tstats);
@@ -2239,9 +2239,15 @@ static void vxlan_encap_bypass(struct sk_buff *skb, struct vxlan_dev *src_vxlan,
22392239
#endif
22402240
}
22412241

2242+
rcu_read_lock();
2243+
dev = skb->dev;
2244+
if (unlikely(!(dev->flags & IFF_UP))) {
2245+
kfree_skb(skb);
2246+
goto drop;
2247+
}
2248+
22422249
if (dst_vxlan->cfg.flags & VXLAN_F_LEARN)
2243-
vxlan_snoop(skb->dev, &loopback, eth_hdr(skb)->h_source, 0,
2244-
vni);
2250+
vxlan_snoop(dev, &loopback, eth_hdr(skb)->h_source, 0, vni);
22452251

22462252
u64_stats_update_begin(&tx_stats->syncp);
22472253
tx_stats->tx_packets++;
@@ -2254,8 +2260,10 @@ static void vxlan_encap_bypass(struct sk_buff *skb, struct vxlan_dev *src_vxlan,
22542260
rx_stats->rx_bytes += len;
22552261
u64_stats_update_end(&rx_stats->syncp);
22562262
} else {
2263+
drop:
22572264
dev->stats.rx_dropped++;
22582265
}
2266+
rcu_read_unlock();
22592267
}
22602268

22612269
static int encap_bypass_if_local(struct sk_buff *skb, struct net_device *dev,

0 commit comments

Comments
 (0)