diff options
author | Eric Dumazet <edumazet@google.com> | 2019-10-30 16:00:04 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2019-10-30 16:24:25 -0400 |
commit | 7170a977743b72cf3eb46ef6ef89885dc7ad3621 (patch) | |
tree | 2f399aeb5a308d3df34fa88d2029c1a4949bf8eb | |
parent | b7265a0df82c1716bf788096217083ed65a8bb14 (diff) |
net: annotate accesses to sk->sk_incoming_cpu
This socket field can be read and written by concurrent cpus.
Use READ_ONCE() and WRITE_ONCE() annotations to document this,
and avoid some compiler 'optimizations'.
KCSAN reported :
BUG: KCSAN: data-race in tcp_v4_rcv / tcp_v4_rcv
write to 0xffff88812220763c of 4 bytes by interrupt on cpu 0:
sk_incoming_cpu_update include/net/sock.h:953 [inline]
tcp_v4_rcv+0x1b3c/0x1bb0 net/ipv4/tcp_ipv4.c:1934
ip_protocol_deliver_rcu+0x4d/0x420 net/ipv4/ip_input.c:204
ip_local_deliver_finish+0x110/0x140 net/ipv4/ip_input.c:231
NF_HOOK include/linux/netfilter.h:305 [inline]
NF_HOOK include/linux/netfilter.h:299 [inline]
ip_local_deliver+0x133/0x210 net/ipv4/ip_input.c:252
dst_input include/net/dst.h:442 [inline]
ip_rcv_finish+0x121/0x160 net/ipv4/ip_input.c:413
NF_HOOK include/linux/netfilter.h:305 [inline]
NF_HOOK include/linux/netfilter.h:299 [inline]
ip_rcv+0x18f/0x1a0 net/ipv4/ip_input.c:523
__netif_receive_skb_one_core+0xa7/0xe0 net/core/dev.c:5010
__netif_receive_skb+0x37/0xf0 net/core/dev.c:5124
process_backlog+0x1d3/0x420 net/core/dev.c:5955
napi_poll net/core/dev.c:6392 [inline]
net_rx_action+0x3ae/0xa90 net/core/dev.c:6460
__do_softirq+0x115/0x33f kernel/softirq.c:292
do_softirq_own_stack+0x2a/0x40 arch/x86/entry/entry_64.S:1082
do_softirq.part.0+0x6b/0x80 kernel/softirq.c:337
do_softirq kernel/softirq.c:329 [inline]
__local_bh_enable_ip+0x76/0x80 kernel/softirq.c:189
read to 0xffff88812220763c of 4 bytes by interrupt on cpu 1:
sk_incoming_cpu_update include/net/sock.h:952 [inline]
tcp_v4_rcv+0x181a/0x1bb0 net/ipv4/tcp_ipv4.c:1934
ip_protocol_deliver_rcu+0x4d/0x420 net/ipv4/ip_input.c:204
ip_local_deliver_finish+0x110/0x140 net/ipv4/ip_input.c:231
NF_HOOK include/linux/netfilter.h:305 [inline]
NF_HOOK include/linux/netfilter.h:299 [inline]
ip_local_deliver+0x133/0x210 net/ipv4/ip_input.c:252
dst_input include/net/dst.h:442 [inline]
ip_rcv_finish+0x121/0x160 net/ipv4/ip_input.c:413
NF_HOOK include/linux/netfilter.h:305 [inline]
NF_HOOK include/linux/netfilter.h:299 [inline]
ip_rcv+0x18f/0x1a0 net/ipv4/ip_input.c:523
__netif_receive_skb_one_core+0xa7/0xe0 net/core/dev.c:5010
__netif_receive_skb+0x37/0xf0 net/core/dev.c:5124
process_backlog+0x1d3/0x420 net/core/dev.c:5955
napi_poll net/core/dev.c:6392 [inline]
net_rx_action+0x3ae/0xa90 net/core/dev.c:6460
__do_softirq+0x115/0x33f kernel/softirq.c:292
run_ksoftirqd+0x46/0x60 kernel/softirq.c:603
smpboot_thread_fn+0x37d/0x4a0 kernel/smpboot.c:165
Reported by Kernel Concurrency Sanitizer on:
CPU: 1 PID: 16 Comm: ksoftirqd/1 Not tainted 5.4.0-rc3+ #0
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011
Signed-off-by: Eric Dumazet <edumazet@google.com>
Reported-by: syzbot <syzkaller@googlegroups.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | include/net/sock.h | 4 | ||||
-rw-r--r-- | net/core/sock.c | 4 | ||||
-rw-r--r-- | net/ipv4/inet_hashtables.c | 2 | ||||
-rw-r--r-- | net/ipv4/udp.c | 2 | ||||
-rw-r--r-- | net/ipv6/inet6_hashtables.c | 2 | ||||
-rw-r--r-- | net/ipv6/udp.c | 2 |
6 files changed, 8 insertions, 8 deletions
diff --git a/include/net/sock.h b/include/net/sock.h index c31a9ed86d5a..8f9adcfac41b 100644 --- a/include/net/sock.h +++ b/include/net/sock.h | |||
@@ -954,8 +954,8 @@ static inline void sk_incoming_cpu_update(struct sock *sk) | |||
954 | { | 954 | { |
955 | int cpu = raw_smp_processor_id(); | 955 | int cpu = raw_smp_processor_id(); |
956 | 956 | ||
957 | if (unlikely(sk->sk_incoming_cpu != cpu)) | 957 | if (unlikely(READ_ONCE(sk->sk_incoming_cpu) != cpu)) |
958 | sk->sk_incoming_cpu = cpu; | 958 | WRITE_ONCE(sk->sk_incoming_cpu, cpu); |
959 | } | 959 | } |
960 | 960 | ||
961 | static inline void sock_rps_record_flow_hash(__u32 hash) | 961 | static inline void sock_rps_record_flow_hash(__u32 hash) |
diff --git a/net/core/sock.c b/net/core/sock.c index b8e758bcb6ad..ac78a570e43a 100644 --- a/net/core/sock.c +++ b/net/core/sock.c | |||
@@ -1127,7 +1127,7 @@ set_rcvbuf: | |||
1127 | break; | 1127 | break; |
1128 | } | 1128 | } |
1129 | case SO_INCOMING_CPU: | 1129 | case SO_INCOMING_CPU: |
1130 | sk->sk_incoming_cpu = val; | 1130 | WRITE_ONCE(sk->sk_incoming_cpu, val); |
1131 | break; | 1131 | break; |
1132 | 1132 | ||
1133 | case SO_CNX_ADVICE: | 1133 | case SO_CNX_ADVICE: |
@@ -1476,7 +1476,7 @@ int sock_getsockopt(struct socket *sock, int level, int optname, | |||
1476 | break; | 1476 | break; |
1477 | 1477 | ||
1478 | case SO_INCOMING_CPU: | 1478 | case SO_INCOMING_CPU: |
1479 | v.val = sk->sk_incoming_cpu; | 1479 | v.val = READ_ONCE(sk->sk_incoming_cpu); |
1480 | break; | 1480 | break; |
1481 | 1481 | ||
1482 | case SO_MEMINFO: | 1482 | case SO_MEMINFO: |
diff --git a/net/ipv4/inet_hashtables.c b/net/ipv4/inet_hashtables.c index 97824864e40d..83fb00153018 100644 --- a/net/ipv4/inet_hashtables.c +++ b/net/ipv4/inet_hashtables.c | |||
@@ -240,7 +240,7 @@ static inline int compute_score(struct sock *sk, struct net *net, | |||
240 | return -1; | 240 | return -1; |
241 | 241 | ||
242 | score = sk->sk_family == PF_INET ? 2 : 1; | 242 | score = sk->sk_family == PF_INET ? 2 : 1; |
243 | if (sk->sk_incoming_cpu == raw_smp_processor_id()) | 243 | if (READ_ONCE(sk->sk_incoming_cpu) == raw_smp_processor_id()) |
244 | score++; | 244 | score++; |
245 | } | 245 | } |
246 | return score; | 246 | return score; |
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index d1ed160af202..1d58ce829dca 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c | |||
@@ -388,7 +388,7 @@ static int compute_score(struct sock *sk, struct net *net, | |||
388 | return -1; | 388 | return -1; |
389 | score += 4; | 389 | score += 4; |
390 | 390 | ||
391 | if (sk->sk_incoming_cpu == raw_smp_processor_id()) | 391 | if (READ_ONCE(sk->sk_incoming_cpu) == raw_smp_processor_id()) |
392 | score++; | 392 | score++; |
393 | return score; | 393 | return score; |
394 | } | 394 | } |
diff --git a/net/ipv6/inet6_hashtables.c b/net/ipv6/inet6_hashtables.c index cf60fae9533b..fbe9d4295eac 100644 --- a/net/ipv6/inet6_hashtables.c +++ b/net/ipv6/inet6_hashtables.c | |||
@@ -105,7 +105,7 @@ static inline int compute_score(struct sock *sk, struct net *net, | |||
105 | return -1; | 105 | return -1; |
106 | 106 | ||
107 | score = 1; | 107 | score = 1; |
108 | if (sk->sk_incoming_cpu == raw_smp_processor_id()) | 108 | if (READ_ONCE(sk->sk_incoming_cpu) == raw_smp_processor_id()) |
109 | score++; | 109 | score++; |
110 | } | 110 | } |
111 | return score; | 111 | return score; |
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 6324d3a8cb53..9fec580c968e 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c | |||
@@ -135,7 +135,7 @@ static int compute_score(struct sock *sk, struct net *net, | |||
135 | return -1; | 135 | return -1; |
136 | score++; | 136 | score++; |
137 | 137 | ||
138 | if (sk->sk_incoming_cpu == raw_smp_processor_id()) | 138 | if (READ_ONCE(sk->sk_incoming_cpu) == raw_smp_processor_id()) |
139 | score++; | 139 | score++; |
140 | 140 | ||
141 | return score; | 141 | return score; |