| From 554cdc88962a871e8ca64e67044b170fe41fffc7 Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Fri, 12 Jan 2024 10:44:27 +0000 |
| Subject: udp: annotate data-races around up->pending |
| |
| From: Eric Dumazet <edumazet@google.com> |
| |
| [ Upstream commit 482521d8e0c6520429478aa6866cd44128b33d5d ] |
| |
| up->pending can be read without holding the socket lock, |
| as pointed out by syzbot [1] |
| |
| Add READ_ONCE() in lockless contexts, and WRITE_ONCE() |
| on write side. |
| |
| [1] |
| BUG: KCSAN: data-race in udpv6_sendmsg / udpv6_sendmsg |
| |
| write to 0xffff88814e5eadf0 of 4 bytes by task 15547 on cpu 1: |
| udpv6_sendmsg+0x1405/0x1530 net/ipv6/udp.c:1596 |
| inet6_sendmsg+0x63/0x80 net/ipv6/af_inet6.c:657 |
| sock_sendmsg_nosec net/socket.c:730 [inline] |
| __sock_sendmsg net/socket.c:745 [inline] |
| __sys_sendto+0x257/0x310 net/socket.c:2192 |
| __do_sys_sendto net/socket.c:2204 [inline] |
| __se_sys_sendto net/socket.c:2200 [inline] |
| __x64_sys_sendto+0x78/0x90 net/socket.c:2200 |
| do_syscall_x64 arch/x86/entry/common.c:52 [inline] |
| do_syscall_64+0x44/0x110 arch/x86/entry/common.c:83 |
| entry_SYSCALL_64_after_hwframe+0x63/0x6b |
| |
| read to 0xffff88814e5eadf0 of 4 bytes by task 15551 on cpu 0: |
| udpv6_sendmsg+0x22c/0x1530 net/ipv6/udp.c:1373 |
| inet6_sendmsg+0x63/0x80 net/ipv6/af_inet6.c:657 |
| sock_sendmsg_nosec net/socket.c:730 [inline] |
| __sock_sendmsg net/socket.c:745 [inline] |
| ____sys_sendmsg+0x37c/0x4d0 net/socket.c:2586 |
| ___sys_sendmsg net/socket.c:2640 [inline] |
| __sys_sendmmsg+0x269/0x500 net/socket.c:2726 |
| __do_sys_sendmmsg net/socket.c:2755 [inline] |
| __se_sys_sendmmsg net/socket.c:2752 [inline] |
| __x64_sys_sendmmsg+0x57/0x60 net/socket.c:2752 |
| do_syscall_x64 arch/x86/entry/common.c:52 [inline] |
| do_syscall_64+0x44/0x110 arch/x86/entry/common.c:83 |
| entry_SYSCALL_64_after_hwframe+0x63/0x6b |
| |
| value changed: 0x00000000 -> 0x0000000a |
| |
| Reported by Kernel Concurrency Sanitizer on: |
| CPU: 0 PID: 15551 Comm: syz-executor.1 Tainted: G W 6.7.0-syzkaller #0 |
| Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 11/17/2023 |
| |
| Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") |
| Reported-by: syzbot+8d482d0e407f665d9d10@syzkaller.appspotmail.com |
| Link: https://lore.kernel.org/netdev/0000000000009e46c3060ebcdffd@google.com/ |
| Signed-off-by: Eric Dumazet <edumazet@google.com> |
| Reviewed-by: Jiri Pirko <jiri@nvidia.com> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| net/ipv4/udp.c | 12 ++++++------ |
| net/ipv6/udp.c | 16 ++++++++-------- |
| 2 files changed, 14 insertions(+), 14 deletions(-) |
| |
| diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c |
| index c3ff984b6354..bd12a7658213 100644 |
| --- a/net/ipv4/udp.c |
| +++ b/net/ipv4/udp.c |
| @@ -805,7 +805,7 @@ void udp_flush_pending_frames(struct sock *sk) |
| |
| if (up->pending) { |
| up->len = 0; |
| - up->pending = 0; |
| + WRITE_ONCE(up->pending, 0); |
| ip_flush_pending_frames(sk); |
| } |
| } |
| @@ -993,7 +993,7 @@ int udp_push_pending_frames(struct sock *sk) |
| |
| out: |
| up->len = 0; |
| - up->pending = 0; |
| + WRITE_ONCE(up->pending, 0); |
| return err; |
| } |
| EXPORT_SYMBOL(udp_push_pending_frames); |
| @@ -1069,7 +1069,7 @@ int udp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) |
| getfrag = is_udplite ? udplite_getfrag : ip_generic_getfrag; |
| |
| fl4 = &inet->cork.fl.u.ip4; |
| - if (up->pending) { |
| + if (READ_ONCE(up->pending)) { |
| /* |
| * There are pending frames. |
| * The socket lock must be held while it's corked. |
| @@ -1265,7 +1265,7 @@ int udp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) |
| fl4->saddr = saddr; |
| fl4->fl4_dport = dport; |
| fl4->fl4_sport = inet->inet_sport; |
| - up->pending = AF_INET; |
| + WRITE_ONCE(up->pending, AF_INET); |
| |
| do_append_data: |
| up->len += ulen; |
| @@ -1277,7 +1277,7 @@ int udp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) |
| else if (!corkreq) |
| err = udp_push_pending_frames(sk); |
| else if (unlikely(skb_queue_empty(&sk->sk_write_queue))) |
| - up->pending = 0; |
| + WRITE_ONCE(up->pending, 0); |
| release_sock(sk); |
| |
| out: |
| @@ -1315,7 +1315,7 @@ void udp_splice_eof(struct socket *sock) |
| struct sock *sk = sock->sk; |
| struct udp_sock *up = udp_sk(sk); |
| |
| - if (!up->pending || udp_test_bit(CORK, sk)) |
| + if (!READ_ONCE(up->pending) || udp_test_bit(CORK, sk)) |
| return; |
| |
| lock_sock(sk); |
| diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c |
| index f60ba4295435..f1170dcc21d9 100644 |
| --- a/net/ipv6/udp.c |
| +++ b/net/ipv6/udp.c |
| @@ -1134,7 +1134,7 @@ static void udp_v6_flush_pending_frames(struct sock *sk) |
| udp_flush_pending_frames(sk); |
| else if (up->pending) { |
| up->len = 0; |
| - up->pending = 0; |
| + WRITE_ONCE(up->pending, 0); |
| ip6_flush_pending_frames(sk); |
| } |
| } |
| @@ -1312,7 +1312,7 @@ static int udp_v6_push_pending_frames(struct sock *sk) |
| &inet_sk(sk)->cork.base); |
| out: |
| up->len = 0; |
| - up->pending = 0; |
| + WRITE_ONCE(up->pending, 0); |
| return err; |
| } |
| |
| @@ -1369,7 +1369,7 @@ int udpv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) |
| default: |
| return -EINVAL; |
| } |
| - } else if (!up->pending) { |
| + } else if (!READ_ONCE(up->pending)) { |
| if (sk->sk_state != TCP_ESTABLISHED) |
| return -EDESTADDRREQ; |
| daddr = &sk->sk_v6_daddr; |
| @@ -1400,8 +1400,8 @@ int udpv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) |
| return -EMSGSIZE; |
| |
| getfrag = is_udplite ? udplite_getfrag : ip_generic_getfrag; |
| - if (up->pending) { |
| - if (up->pending == AF_INET) |
| + if (READ_ONCE(up->pending)) { |
| + if (READ_ONCE(up->pending) == AF_INET) |
| return udp_sendmsg(sk, msg, len); |
| /* |
| * There are pending frames. |
| @@ -1591,7 +1591,7 @@ int udpv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) |
| goto out; |
| } |
| |
| - up->pending = AF_INET6; |
| + WRITE_ONCE(up->pending, AF_INET6); |
| |
| do_append_data: |
| if (ipc6.dontfrag < 0) |
| @@ -1605,7 +1605,7 @@ int udpv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) |
| else if (!corkreq) |
| err = udp_v6_push_pending_frames(sk); |
| else if (unlikely(skb_queue_empty(&sk->sk_write_queue))) |
| - up->pending = 0; |
| + WRITE_ONCE(up->pending, 0); |
| |
| if (err > 0) |
| err = np->recverr ? net_xmit_errno(err) : 0; |
| @@ -1646,7 +1646,7 @@ static void udpv6_splice_eof(struct socket *sock) |
| struct sock *sk = sock->sk; |
| struct udp_sock *up = udp_sk(sk); |
| |
| - if (!up->pending || udp_test_bit(CORK, sk)) |
| + if (!READ_ONCE(up->pending) || udp_test_bit(CORK, sk)) |
| return; |
| |
| lock_sock(sk); |
| -- |
| 2.43.0 |
| |