Skip to content

Commit d95d632

Browse files
edumazetkuba-moo
authored andcommitted
ipv6: fix data-race in fib6_info_hw_flags_set / fib6_purge_rt
Because fib6_info_hw_flags_set() is called without any synchronization, all accesses to gi6->offload, fi->trap and fi->offload_failed need some basic protection like READ_ONCE()/WRITE_ONCE(). BUG: KCSAN: data-race in fib6_info_hw_flags_set / fib6_purge_rt read to 0xffff8881087d5886 of 1 bytes by task 13953 on cpu 0: fib6_drop_pcpu_from net/ipv6/ip6_fib.c:1007 [inline] fib6_purge_rt+0x4f/0x580 net/ipv6/ip6_fib.c:1033 fib6_del_route net/ipv6/ip6_fib.c:1983 [inline] fib6_del+0x696/0x890 net/ipv6/ip6_fib.c:2028 __ip6_del_rt net/ipv6/route.c:3876 [inline] ip6_del_rt+0x83/0x140 net/ipv6/route.c:3891 __ipv6_dev_ac_dec+0x2b5/0x370 net/ipv6/anycast.c:374 ipv6_dev_ac_dec net/ipv6/anycast.c:387 [inline] __ipv6_sock_ac_close+0x141/0x200 net/ipv6/anycast.c:207 ipv6_sock_ac_close+0x79/0x90 net/ipv6/anycast.c:220 inet6_release+0x32/0x50 net/ipv6/af_inet6.c:476 __sock_release net/socket.c:650 [inline] sock_close+0x6c/0x150 net/socket.c:1318 __fput+0x295/0x520 fs/file_table.c:280 ____fput+0x11/0x20 fs/file_table.c:313 task_work_run+0x8e/0x110 kernel/task_work.c:164 tracehook_notify_resume include/linux/tracehook.h:189 [inline] exit_to_user_mode_loop kernel/entry/common.c:175 [inline] exit_to_user_mode_prepare+0x160/0x190 kernel/entry/common.c:207 __syscall_exit_to_user_mode_work kernel/entry/common.c:289 [inline] syscall_exit_to_user_mode+0x20/0x40 kernel/entry/common.c:300 do_syscall_64+0x50/0xd0 arch/x86/entry/common.c:86 entry_SYSCALL_64_after_hwframe+0x44/0xae write to 0xffff8881087d5886 of 1 bytes by task 1912 on cpu 1: fib6_info_hw_flags_set+0x155/0x3b0 net/ipv6/route.c:6230 nsim_fib6_rt_hw_flags_set drivers/net/netdevsim/fib.c:668 [inline] nsim_fib6_rt_add drivers/net/netdevsim/fib.c:691 [inline] nsim_fib6_rt_insert drivers/net/netdevsim/fib.c:756 [inline] nsim_fib6_event drivers/net/netdevsim/fib.c:853 [inline] nsim_fib_event drivers/net/netdevsim/fib.c:886 [inline] nsim_fib_event_work+0x284f/0x2cf0 drivers/net/netdevsim/fib.c:1477 process_one_work+0x3f6/0x960 kernel/workqueue.c:2307 worker_thread+0x616/0xa70 kernel/workqueue.c:2454 kthread+0x2c7/0x2e0 kernel/kthread.c:327 ret_from_fork+0x1f/0x30 value changed: 0x22 -> 0x2a Reported by Kernel Concurrency Sanitizer on: CPU: 1 PID: 1912 Comm: kworker/1:3 Not tainted 5.16.0-syzkaller #0 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 Workqueue: events nsim_fib_event_work Fixes: 0c5fcf9 ("IPv6: Add "offload failed" indication to routes") Fixes: bb3c4ab ("ipv6: Add "offload" and "trap" indications to routes") Signed-off-by: Eric Dumazet <edumazet@google.com> Cc: Amit Cohen <amcohen@nvidia.com> Cc: Ido Schimmel <idosch@nvidia.com> Reported-by: syzbot <syzkaller@googlegroups.com> Link: https://lore.kernel.org/r/20220216173217.3792411-2-eric.dumazet@gmail.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
1 parent 9fcf986 commit d95d632

File tree

3 files changed

+18
-15
lines changed

3 files changed

+18
-15
lines changed

drivers/net/netdevsim/fib.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -623,14 +623,14 @@ static int nsim_fib6_rt_append(struct nsim_fib_data *data,
623623
if (err)
624624
goto err_fib6_rt_nh_del;
625625

626-
fib6_event->rt_arr[i]->trap = true;
626+
WRITE_ONCE(fib6_event->rt_arr[i]->trap, true);
627627
}
628628

629629
return 0;
630630

631631
err_fib6_rt_nh_del:
632632
for (i--; i >= 0; i--) {
633-
fib6_event->rt_arr[i]->trap = false;
633+
WRITE_ONCE(fib6_event->rt_arr[i]->trap, false);
634634
nsim_fib6_rt_nh_del(fib6_rt, fib6_event->rt_arr[i]);
635635
}
636636
return err;

include/net/ip6_fib.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -190,14 +190,16 @@ struct fib6_info {
190190
u32 fib6_metric;
191191
u8 fib6_protocol;
192192
u8 fib6_type;
193+
194+
u8 offload;
195+
u8 trap;
196+
u8 offload_failed;
197+
193198
u8 should_flush:1,
194199
dst_nocount:1,
195200
dst_nopolicy:1,
196201
fib6_destroying:1,
197-
offload:1,
198-
trap:1,
199-
offload_failed:1,
200-
unused:1;
202+
unused:4;
201203

202204
struct rcu_head rcu;
203205
struct nexthop *nh;

net/ipv6/route.c

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5753,11 +5753,11 @@ static int rt6_fill_node(struct net *net, struct sk_buff *skb,
57535753
}
57545754

57555755
if (!dst) {
5756-
if (rt->offload)
5756+
if (READ_ONCE(rt->offload))
57575757
rtm->rtm_flags |= RTM_F_OFFLOAD;
5758-
if (rt->trap)
5758+
if (READ_ONCE(rt->trap))
57595759
rtm->rtm_flags |= RTM_F_TRAP;
5760-
if (rt->offload_failed)
5760+
if (READ_ONCE(rt->offload_failed))
57615761
rtm->rtm_flags |= RTM_F_OFFLOAD_FAILED;
57625762
}
57635763

@@ -6215,19 +6215,20 @@ void fib6_info_hw_flags_set(struct net *net, struct fib6_info *f6i,
62156215
struct sk_buff *skb;
62166216
int err;
62176217

6218-
if (f6i->offload == offload && f6i->trap == trap &&
6219-
f6i->offload_failed == offload_failed)
6218+
if (READ_ONCE(f6i->offload) == offload &&
6219+
READ_ONCE(f6i->trap) == trap &&
6220+
READ_ONCE(f6i->offload_failed) == offload_failed)
62206221
return;
62216222

6222-
f6i->offload = offload;
6223-
f6i->trap = trap;
6223+
WRITE_ONCE(f6i->offload, offload);
6224+
WRITE_ONCE(f6i->trap, trap);
62246225

62256226
/* 2 means send notifications only if offload_failed was changed. */
62266227
if (net->ipv6.sysctl.fib_notify_on_flag_change == 2 &&
6227-
f6i->offload_failed == offload_failed)
6228+
READ_ONCE(f6i->offload_failed) == offload_failed)
62286229
return;
62296230

6230-
f6i->offload_failed = offload_failed;
6231+
WRITE_ONCE(f6i->offload_failed, offload_failed);
62316232

62326233
if (!rcu_access_pointer(f6i->fib6_node))
62336234
/* The route was removed from the tree, do not send

0 commit comments

Comments
 (0)