| From 47cf47f52d8515682c44a18bd68e5a869003d013 Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Tue, 4 Feb 2025 16:55:42 +0200 |
| Subject: vxlan: Annotate FDB data races |
| |
| From: Ido Schimmel <idosch@nvidia.com> |
| |
| [ Upstream commit f6205f8215f12a96518ac9469ff76294ae7bd612 ] |
| |
| The 'used' and 'updated' fields in the FDB entry structure can be |
| accessed concurrently by multiple threads, leading to reports such as |
| [1]. Can be reproduced using [2]. |
| |
| Suppress these reports by annotating these accesses using |
| READ_ONCE() / WRITE_ONCE(). |
| |
| [1] |
| BUG: KCSAN: data-race in vxlan_xmit / vxlan_xmit |
| |
| write to 0xffff942604d263a8 of 8 bytes by task 286 on cpu 0: |
| vxlan_xmit+0xb29/0x2380 |
| dev_hard_start_xmit+0x84/0x2f0 |
| __dev_queue_xmit+0x45a/0x1650 |
| packet_xmit+0x100/0x150 |
| packet_sendmsg+0x2114/0x2ac0 |
| __sys_sendto+0x318/0x330 |
| __x64_sys_sendto+0x76/0x90 |
| x64_sys_call+0x14e8/0x1c00 |
| do_syscall_64+0x9e/0x1a0 |
| entry_SYSCALL_64_after_hwframe+0x77/0x7f |
| |
| read to 0xffff942604d263a8 of 8 bytes by task 287 on cpu 2: |
| vxlan_xmit+0xadf/0x2380 |
| dev_hard_start_xmit+0x84/0x2f0 |
| __dev_queue_xmit+0x45a/0x1650 |
| packet_xmit+0x100/0x150 |
| packet_sendmsg+0x2114/0x2ac0 |
| __sys_sendto+0x318/0x330 |
| __x64_sys_sendto+0x76/0x90 |
| x64_sys_call+0x14e8/0x1c00 |
| do_syscall_64+0x9e/0x1a0 |
| entry_SYSCALL_64_after_hwframe+0x77/0x7f |
| |
| value changed: 0x00000000fffbac6e -> 0x00000000fffbac6f |
| |
| Reported by Kernel Concurrency Sanitizer on: |
| CPU: 2 UID: 0 PID: 287 Comm: mausezahn Not tainted 6.13.0-rc7-01544-gb4b270f11a02 #5 |
| Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.16.3-3.fc41 04/01/2014 |
| |
| [2] |
| #!/bin/bash |
| |
| set +H |
| echo whitelist > /sys/kernel/debug/kcsan |
| echo !vxlan_xmit > /sys/kernel/debug/kcsan |
| |
| ip link add name vx0 up type vxlan id 10010 dstport 4789 local 192.0.2.1 |
| bridge fdb add 00:11:22:33:44:55 dev vx0 self static dst 198.51.100.1 |
| taskset -c 0 mausezahn vx0 -a own -b 00:11:22:33:44:55 -c 0 -q & |
| taskset -c 2 mausezahn vx0 -a own -b 00:11:22:33:44:55 -c 0 -q & |
| |
| Reviewed-by: Petr Machata <petrm@nvidia.com> |
| Signed-off-by: Ido Schimmel <idosch@nvidia.com> |
| Reviewed-by: Eric Dumazet <edumazet@google.com> |
| Reviewed-by: Nikolay Aleksandrov <razor@blackwall.org> |
| Link: https://patch.msgid.link/20250204145549.1216254-2-idosch@nvidia.com |
| Signed-off-by: Jakub Kicinski <kuba@kernel.org> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| drivers/net/vxlan.c | 18 +++++++++--------- |
| 1 file changed, 9 insertions(+), 9 deletions(-) |
| |
| diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c |
| index ce11fb2b05561..7105ac37f341e 100644 |
| --- a/drivers/net/vxlan.c |
| +++ b/drivers/net/vxlan.c |
| @@ -302,9 +302,9 @@ static int vxlan_fdb_info(struct sk_buff *skb, struct vxlan_dev *vxlan, |
| nla_put_u32(skb, NDA_IFINDEX, rdst->remote_ifindex)) |
| goto nla_put_failure; |
| |
| - ci.ndm_used = jiffies_to_clock_t(now - fdb->used); |
| + ci.ndm_used = jiffies_to_clock_t(now - READ_ONCE(fdb->used)); |
| ci.ndm_confirmed = 0; |
| - ci.ndm_updated = jiffies_to_clock_t(now - fdb->updated); |
| + ci.ndm_updated = jiffies_to_clock_t(now - READ_ONCE(fdb->updated)); |
| ci.ndm_refcnt = 0; |
| |
| if (nla_put(skb, NDA_CACHEINFO, sizeof(ci), &ci)) |
| @@ -510,8 +510,8 @@ static struct vxlan_fdb *vxlan_find_mac(struct vxlan_dev *vxlan, |
| struct vxlan_fdb *f; |
| |
| f = __vxlan_find_mac(vxlan, mac, vni); |
| - if (f && f->used != jiffies) |
| - f->used = jiffies; |
| + if (f && READ_ONCE(f->used) != jiffies) |
| + WRITE_ONCE(f->used, jiffies); |
| |
| return f; |
| } |
| @@ -942,12 +942,12 @@ static int vxlan_fdb_update_existing(struct vxlan_dev *vxlan, |
| !(f->flags & NTF_VXLAN_ADDED_BY_USER)) { |
| if (f->state != state) { |
| f->state = state; |
| - f->updated = jiffies; |
| + WRITE_ONCE(f->updated, jiffies); |
| notify = 1; |
| } |
| if (f->flags != fdb_flags) { |
| f->flags = fdb_flags; |
| - f->updated = jiffies; |
| + WRITE_ONCE(f->updated, jiffies); |
| notify = 1; |
| } |
| } |
| @@ -974,7 +974,7 @@ static int vxlan_fdb_update_existing(struct vxlan_dev *vxlan, |
| } |
| |
| if (ndm_flags & NTF_USE) |
| - f->used = jiffies; |
| + WRITE_ONCE(f->used, jiffies); |
| |
| if (notify) { |
| if (rd == NULL) |
| @@ -1351,7 +1351,7 @@ static bool vxlan_snoop(struct net_device *dev, |
| src_mac, &rdst->remote_ip.sa, &src_ip->sa); |
| |
| rdst->remote_ip = *src_ip; |
| - f->updated = jiffies; |
| + WRITE_ONCE(f->updated, jiffies); |
| vxlan_fdb_notify(vxlan, f, rdst, RTM_NEWNEIGH, true, NULL); |
| } else { |
| u32 hash_index = fdb_head_index(vxlan, src_mac, vni); |
| @@ -2748,7 +2748,7 @@ static void vxlan_cleanup(struct timer_list *t) |
| if (f->flags & NTF_EXT_LEARNED) |
| continue; |
| |
| - timeout = f->used + vxlan->cfg.age_interval * HZ; |
| + timeout = READ_ONCE(f->used) + vxlan->cfg.age_interval * HZ; |
| if (time_before_eq(timeout, jiffies)) { |
| netdev_dbg(vxlan->dev, |
| "garbage collect %pM\n", |
| -- |
| 2.39.5 |
| |