summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Dumazet <edumazet@google.com>2026-07-23 14:42:47 +0000
committerJakub Kicinski <kuba@kernel.org>2026-07-27 15:15:13 -0700
commit8eca411347e1d38964f9ed2c8d3b6ab0e7e4473d (patch)
treebc988f54a17af34c9cb7dc4bf8c5b02a102ea282
parent760d36e737f2b3867762f42af36c663f55babcc4 (diff)
downloadlinux-next-8eca411347e1d38964f9ed2c8d3b6ab0e7e4473d.tar.gz
linux-next-8eca411347e1d38964f9ed2c8d3b6ab0e7e4473d.zip
vxlan: use neigh_ha_snapshot() in route_shortcircuit()
The neighbour hardware address n->ha can be updated asynchronously by the neighbour subsystem, protected by n->ha_lock seqlock. Reading n->ha without holding the seqlock loop can lead to torn reads or reading a partially updated MAC address. Use neigh_ha_snapshot() in route_shortcircuit() to safely copy n->ha under read_seqbegin()/read_seqretry() lock protection before using it. Note that arp_reduce() and neigh_reduce() seem to have the same issue left for future patches. Fixes: e4f67addf158 ("add DOVE extensions for VXLAN") Cc: stable@vger.kernel.org Signed-off-by: Eric Dumazet <edumazet@google.com> Reviewed-by: Vadim Fedorenko <vadim.fedorenko@linux.dev> Link: https://patch.msgid.link/20260723144249.759100-4-edumazet@google.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
-rw-r--r--drivers/net/vxlan/vxlan_core.c6
1 files changed, 4 insertions, 2 deletions
diff --git a/drivers/net/vxlan/vxlan_core.c b/drivers/net/vxlan/vxlan_core.c
index e831fe203442..be3c2bc2cd9a 100644
--- a/drivers/net/vxlan/vxlan_core.c
+++ b/drivers/net/vxlan/vxlan_core.c
@@ -2159,9 +2159,11 @@ static bool route_shortcircuit(struct net_device *dev, struct sk_buff *skb)
}
if (n) {
+ u8 haddr[ETH_ALEN];
bool diff;
- diff = !ether_addr_equal(eth_hdr(skb)->h_dest, n->ha);
+ neigh_ha_snapshot(haddr, n, dev);
+ diff = !ether_addr_equal_unaligned(eth_hdr(skb)->h_dest, haddr);
if (diff) {
if (skb_cow_head(skb, 0)) {
neigh_release(n);
@@ -2169,7 +2171,7 @@ static bool route_shortcircuit(struct net_device *dev, struct sk_buff *skb)
}
memcpy(eth_hdr(skb)->h_source, eth_hdr(skb)->h_dest,
dev->addr_len);
- memcpy(eth_hdr(skb)->h_dest, n->ha, dev->addr_len);
+ memcpy(eth_hdr(skb)->h_dest, haddr, dev->addr_len);
}
neigh_release(n);
return diff;