From: Greg Kroah-Hartman Date: Tue, 2 Jul 2024 09:50:51 +0000 (+0200) Subject: 5.10-stable patches X-Git-Tag: v4.19.317~46 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=a96c306ba6e203f07c0308e481dc4345fed5ba75;p=thirdparty%2Fkernel%2Fstable-queue.git 5.10-stable patches added patches: ipv6-annotate-some-data-races-around-sk-sk_prot.patch ipv6-fix-data-races-around-sk-sk_prot.patch tcp-fix-data-races-around-icsk-icsk_af_ops.patch --- diff --git a/queue-5.10/ipv6-annotate-some-data-races-around-sk-sk_prot.patch b/queue-5.10/ipv6-annotate-some-data-races-around-sk-sk_prot.patch new file mode 100644 index 00000000000..b7858a4de96 --- /dev/null +++ b/queue-5.10/ipv6-annotate-some-data-races-around-sk-sk_prot.patch @@ -0,0 +1,167 @@ +From stable+bounces-56035-greg=kroah.com@vger.kernel.org Fri Jun 28 07:39:00 2024 +From: Kazunori Kobayashi +Date: Mon, 17 Apr 2023 16:50:32 +0000 +Subject: ipv6: annotate some data-races around sk->sk_prot +To: netdev@vger.kernel.org +Cc: stable@vger.kernel.org, linux-kernel@vger.kernel.org, hiraku.toyooka@miraclelinux.com, Eric Dumazet , "David S . Miller" , Kazunori Kobayashi +Message-ID: <20230417165034.26123-2-kazunori.kobayashi@miraclelinux.com> + +From: Eric Dumazet + +commit 086d49058cd8471046ae9927524708820f5fd1c7 upstream. + +IPv6 has this hack changing sk->sk_prot when an IPv6 socket +is 'converted' to an IPv4 one with IPV6_ADDRFORM option. + +This operation is only performed for TCP and UDP, knowing +their 'struct proto' for the two network families are populated +in the same way, and can not disappear while a reader +might use and dereference sk->sk_prot. + +If we think about it all reads of sk->sk_prot while +either socket lock or RTNL is not acquired should be using READ_ONCE(). + +Also note that other layers like MPTCP, XFRM, CHELSIO_TLS also +write over sk->sk_prot. + +BUG: KCSAN: data-race in inet6_recvmsg / ipv6_setsockopt + +write to 0xffff8881386f7aa8 of 8 bytes by task 26932 on cpu 0: + do_ipv6_setsockopt net/ipv6/ipv6_sockglue.c:492 [inline] + ipv6_setsockopt+0x3758/0x3910 net/ipv6/ipv6_sockglue.c:1019 + udpv6_setsockopt+0x85/0x90 net/ipv6/udp.c:1649 + sock_common_setsockopt+0x5d/0x70 net/core/sock.c:3489 + __sys_setsockopt+0x209/0x2a0 net/socket.c:2180 + __do_sys_setsockopt net/socket.c:2191 [inline] + __se_sys_setsockopt net/socket.c:2188 [inline] + __x64_sys_setsockopt+0x62/0x70 net/socket.c:2188 + do_syscall_x64 arch/x86/entry/common.c:50 [inline] + do_syscall_64+0x44/0xd0 arch/x86/entry/common.c:80 + entry_SYSCALL_64_after_hwframe+0x44/0xae + +read to 0xffff8881386f7aa8 of 8 bytes by task 26911 on cpu 1: + inet6_recvmsg+0x7a/0x210 net/ipv6/af_inet6.c:659 + ____sys_recvmsg+0x16c/0x320 + ___sys_recvmsg net/socket.c:2674 [inline] + do_recvmmsg+0x3f5/0xae0 net/socket.c:2768 + __sys_recvmmsg net/socket.c:2847 [inline] + __do_sys_recvmmsg net/socket.c:2870 [inline] + __se_sys_recvmmsg net/socket.c:2863 [inline] + __x64_sys_recvmmsg+0xde/0x160 net/socket.c:2863 + do_syscall_x64 arch/x86/entry/common.c:50 [inline] + do_syscall_64+0x44/0xd0 arch/x86/entry/common.c:80 + entry_SYSCALL_64_after_hwframe+0x44/0xae + +value changed: 0xffffffff85e0e980 -> 0xffffffff85e01580 + +Reported by Kernel Concurrency Sanitizer on: +CPU: 1 PID: 26911 Comm: syz-executor.3 Not tainted 5.17.0-rc2-syzkaller-00316-g0457e5153e0e-dirty #0 +Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 + +Reported-by: syzbot +Signed-off-by: Eric Dumazet +Signed-off-by: David S. Miller +Signed-off-by: Kazunori Kobayashi +Signed-off-by: Greg Kroah-Hartman +--- + net/ipv6/af_inet6.c | 24 ++++++++++++++++++------ + net/ipv6/ipv6_sockglue.c | 6 ++++-- + 2 files changed, 22 insertions(+), 8 deletions(-) + +--- a/net/ipv6/af_inet6.c ++++ b/net/ipv6/af_inet6.c +@@ -449,11 +449,14 @@ out_unlock: + int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) + { + struct sock *sk = sock->sk; ++ const struct proto *prot; + int err = 0; + ++ /* IPV6_ADDRFORM can change sk->sk_prot under us. */ ++ prot = READ_ONCE(sk->sk_prot); + /* If the socket has its own bind function then use it. */ +- if (sk->sk_prot->bind) +- return sk->sk_prot->bind(sk, uaddr, addr_len); ++ if (prot->bind) ++ return prot->bind(sk, uaddr, addr_len); + + if (addr_len < SIN6_LEN_RFC2133) + return -EINVAL; +@@ -566,6 +569,7 @@ int inet6_ioctl(struct socket *sock, uns + void __user *argp = (void __user *)arg; + struct sock *sk = sock->sk; + struct net *net = sock_net(sk); ++ const struct proto *prot; + + switch (cmd) { + case SIOCADDRT: +@@ -583,9 +587,11 @@ int inet6_ioctl(struct socket *sock, uns + case SIOCSIFDSTADDR: + return addrconf_set_dstaddr(net, argp); + default: +- if (!sk->sk_prot->ioctl) ++ /* IPV6_ADDRFORM can change sk->sk_prot under us. */ ++ prot = READ_ONCE(sk->sk_prot); ++ if (!prot->ioctl) + return -ENOIOCTLCMD; +- return sk->sk_prot->ioctl(sk, cmd, arg); ++ return prot->ioctl(sk, cmd, arg); + } + /*NOTREACHED*/ + return 0; +@@ -647,11 +653,14 @@ INDIRECT_CALLABLE_DECLARE(int udpv6_send + int inet6_sendmsg(struct socket *sock, struct msghdr *msg, size_t size) + { + struct sock *sk = sock->sk; ++ const struct proto *prot; + + if (unlikely(inet_send_prepare(sk))) + return -EAGAIN; + +- return INDIRECT_CALL_2(sk->sk_prot->sendmsg, tcp_sendmsg, udpv6_sendmsg, ++ /* IPV6_ADDRFORM can change sk->sk_prot under us. */ ++ prot = READ_ONCE(sk->sk_prot); ++ return INDIRECT_CALL_2(prot->sendmsg, tcp_sendmsg, udpv6_sendmsg, + sk, msg, size); + } + +@@ -661,13 +670,16 @@ int inet6_recvmsg(struct socket *sock, s + int flags) + { + struct sock *sk = sock->sk; ++ const struct proto *prot; + int addr_len = 0; + int err; + + if (likely(!(flags & MSG_ERRQUEUE))) + sock_rps_record_flow(sk); + +- err = INDIRECT_CALL_2(sk->sk_prot->recvmsg, tcp_recvmsg, udpv6_recvmsg, ++ /* IPV6_ADDRFORM can change sk->sk_prot under us. */ ++ prot = READ_ONCE(sk->sk_prot); ++ err = INDIRECT_CALL_2(prot->recvmsg, tcp_recvmsg, udpv6_recvmsg, + sk, msg, size, flags & MSG_DONTWAIT, + flags & ~MSG_DONTWAIT, &addr_len); + if (err >= 0) +--- a/net/ipv6/ipv6_sockglue.c ++++ b/net/ipv6/ipv6_sockglue.c +@@ -475,7 +475,8 @@ static int do_ipv6_setsockopt(struct soc + sock_prot_inuse_add(net, sk->sk_prot, -1); + sock_prot_inuse_add(net, &tcp_prot, 1); + local_bh_enable(); +- sk->sk_prot = &tcp_prot; ++ /* Paired with READ_ONCE(sk->sk_prot) in net/ipv6/af_inet6.c */ ++ WRITE_ONCE(sk->sk_prot, &tcp_prot); + icsk->icsk_af_ops = &ipv4_specific; + sk->sk_socket->ops = &inet_stream_ops; + sk->sk_family = PF_INET; +@@ -489,7 +490,8 @@ static int do_ipv6_setsockopt(struct soc + sock_prot_inuse_add(net, sk->sk_prot, -1); + sock_prot_inuse_add(net, prot, 1); + local_bh_enable(); +- sk->sk_prot = prot; ++ /* Paired with READ_ONCE(sk->sk_prot) in net/ipv6/af_inet6.c */ ++ WRITE_ONCE(sk->sk_prot, prot); + sk->sk_socket->ops = &inet_dgram_ops; + sk->sk_family = PF_INET; + } diff --git a/queue-5.10/ipv6-fix-data-races-around-sk-sk_prot.patch b/queue-5.10/ipv6-fix-data-races-around-sk-sk_prot.patch new file mode 100644 index 00000000000..f1e1ee399b3 --- /dev/null +++ b/queue-5.10/ipv6-fix-data-races-around-sk-sk_prot.patch @@ -0,0 +1,137 @@ +From stable+bounces-56036-greg=kroah.com@vger.kernel.org Fri Jun 28 07:39:11 2024 +From: Kazunori Kobayashi +Date: Mon, 17 Apr 2023 16:50:33 +0000 +Subject: ipv6: Fix data races around sk->sk_prot. +To: netdev@vger.kernel.org +Cc: stable@vger.kernel.org, linux-kernel@vger.kernel.org, hiraku.toyooka@miraclelinux.com, Kuniyuki Iwashima , Jakub Kicinski , Kazunori Kobayashi +Message-ID: <20230417165034.26123-3-kazunori.kobayashi@miraclelinux.com> + +From: Kuniyuki Iwashima + +commit 364f997b5cfe1db0d63a390fe7c801fa2b3115f6 upstream. + +Commit 086d49058cd8 ("ipv6: annotate some data-races around sk->sk_prot") +fixed some data-races around sk->sk_prot but it was not enough. + +Some functions in inet6_(stream|dgram)_ops still access sk->sk_prot +without lock_sock() or rtnl_lock(), so they need READ_ONCE() to avoid +load tearing. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Signed-off-by: Kuniyuki Iwashima +Signed-off-by: Jakub Kicinski +Signed-off-by: Kazunori Kobayashi +Signed-off-by: Greg Kroah-Hartman +--- + net/core/sock.c | 6 ++++-- + net/ipv4/af_inet.c | 23 ++++++++++++++++------- + net/ipv6/ipv6_sockglue.c | 4 ++-- + 3 files changed, 22 insertions(+), 11 deletions(-) + +--- a/net/core/sock.c ++++ b/net/core/sock.c +@@ -3263,7 +3263,8 @@ int sock_common_getsockopt(struct socket + { + struct sock *sk = sock->sk; + +- return sk->sk_prot->getsockopt(sk, level, optname, optval, optlen); ++ /* IPV6_ADDRFORM can change sk->sk_prot under us. */ ++ return READ_ONCE(sk->sk_prot)->getsockopt(sk, level, optname, optval, optlen); + } + EXPORT_SYMBOL(sock_common_getsockopt); + +@@ -3290,7 +3291,8 @@ int sock_common_setsockopt(struct socket + { + struct sock *sk = sock->sk; + +- return sk->sk_prot->setsockopt(sk, level, optname, optval, optlen); ++ /* IPV6_ADDRFORM can change sk->sk_prot under us. */ ++ return READ_ONCE(sk->sk_prot)->setsockopt(sk, level, optname, optval, optlen); + } + EXPORT_SYMBOL(sock_common_setsockopt); + +--- a/net/ipv4/af_inet.c ++++ b/net/ipv4/af_inet.c +@@ -562,22 +562,27 @@ int inet_dgram_connect(struct socket *so + int addr_len, int flags) + { + struct sock *sk = sock->sk; ++ const struct proto *prot; + int err; + + if (addr_len < sizeof(uaddr->sa_family)) + return -EINVAL; ++ ++ /* IPV6_ADDRFORM can change sk->sk_prot under us. */ ++ prot = READ_ONCE(sk->sk_prot); ++ + if (uaddr->sa_family == AF_UNSPEC) +- return sk->sk_prot->disconnect(sk, flags); ++ return prot->disconnect(sk, flags); + + if (BPF_CGROUP_PRE_CONNECT_ENABLED(sk)) { +- err = sk->sk_prot->pre_connect(sk, uaddr, addr_len); ++ err = prot->pre_connect(sk, uaddr, addr_len); + if (err) + return err; + } + + if (data_race(!inet_sk(sk)->inet_num) && inet_autobind(sk)) + return -EAGAIN; +- return sk->sk_prot->connect(sk, uaddr, addr_len); ++ return prot->connect(sk, uaddr, addr_len); + } + EXPORT_SYMBOL(inet_dgram_connect); + +@@ -740,10 +745,11 @@ EXPORT_SYMBOL(inet_stream_connect); + int inet_accept(struct socket *sock, struct socket *newsock, int flags, + bool kern) + { +- struct sock *sk1 = sock->sk; ++ struct sock *sk1 = sock->sk, *sk2; + int err = -EINVAL; +- struct sock *sk2 = sk1->sk_prot->accept(sk1, flags, &err, kern); + ++ /* IPV6_ADDRFORM can change sk->sk_prot under us. */ ++ sk2 = READ_ONCE(sk1->sk_prot)->accept(sk1, flags, &err, kern); + if (!sk2) + goto do_err; + +@@ -828,12 +834,15 @@ ssize_t inet_sendpage(struct socket *soc + size_t size, int flags) + { + struct sock *sk = sock->sk; ++ const struct proto *prot; + + if (unlikely(inet_send_prepare(sk))) + return -EAGAIN; + +- if (sk->sk_prot->sendpage) +- return sk->sk_prot->sendpage(sk, page, offset, size, flags); ++ /* IPV6_ADDRFORM can change sk->sk_prot under us. */ ++ prot = READ_ONCE(sk->sk_prot); ++ if (prot->sendpage) ++ return prot->sendpage(sk, page, offset, size, flags); + return sock_no_sendpage(sock, page, offset, size, flags); + } + EXPORT_SYMBOL(inet_sendpage); +--- a/net/ipv6/ipv6_sockglue.c ++++ b/net/ipv6/ipv6_sockglue.c +@@ -475,7 +475,7 @@ static int do_ipv6_setsockopt(struct soc + sock_prot_inuse_add(net, sk->sk_prot, -1); + sock_prot_inuse_add(net, &tcp_prot, 1); + local_bh_enable(); +- /* Paired with READ_ONCE(sk->sk_prot) in net/ipv6/af_inet6.c */ ++ /* Paired with READ_ONCE(sk->sk_prot) in inet6_stream_ops */ + WRITE_ONCE(sk->sk_prot, &tcp_prot); + icsk->icsk_af_ops = &ipv4_specific; + sk->sk_socket->ops = &inet_stream_ops; +@@ -490,7 +490,7 @@ static int do_ipv6_setsockopt(struct soc + sock_prot_inuse_add(net, sk->sk_prot, -1); + sock_prot_inuse_add(net, prot, 1); + local_bh_enable(); +- /* Paired with READ_ONCE(sk->sk_prot) in net/ipv6/af_inet6.c */ ++ /* Paired with READ_ONCE(sk->sk_prot) in inet6_dgram_ops */ + WRITE_ONCE(sk->sk_prot, prot); + sk->sk_socket->ops = &inet_dgram_ops; + sk->sk_family = PF_INET; diff --git a/queue-5.10/series b/queue-5.10/series index 32d43e37151..09662438ee3 100644 --- a/queue-5.10/series +++ b/queue-5.10/series @@ -329,3 +329,6 @@ syscalls-fix-compat_sys_io_pgetevents_time64-usage.patch mtd-spinand-macronix-add-support-for-serial-nand-flash.patch pwm-stm32-refuse-too-small-period-requests.patch nfs-leave-pages-in-the-pagecache-if-readpage-failed.patch +ipv6-annotate-some-data-races-around-sk-sk_prot.patch +ipv6-fix-data-races-around-sk-sk_prot.patch +tcp-fix-data-races-around-icsk-icsk_af_ops.patch diff --git a/queue-5.10/tcp-fix-data-races-around-icsk-icsk_af_ops.patch b/queue-5.10/tcp-fix-data-races-around-icsk-icsk_af_ops.patch new file mode 100644 index 00000000000..f61d3934f2e --- /dev/null +++ b/queue-5.10/tcp-fix-data-races-around-icsk-icsk_af_ops.patch @@ -0,0 +1,127 @@ +From stable+bounces-56037-greg=kroah.com@vger.kernel.org Fri Jun 28 07:39:30 2024 +From: Kazunori Kobayashi +Date: Mon, 17 Apr 2023 16:50:34 +0000 +Subject: tcp: Fix data races around icsk->icsk_af_ops. +To: netdev@vger.kernel.org +Cc: stable@vger.kernel.org, linux-kernel@vger.kernel.org, hiraku.toyooka@miraclelinux.com, Kuniyuki Iwashima , Jakub Kicinski , Kazunori Kobayashi +Message-ID: <20230417165034.26123-4-kazunori.kobayashi@miraclelinux.com> + +From: Kuniyuki Iwashima + +commit f49cd2f4d6170d27a2c61f1fecb03d8a70c91f57 upstream. + +setsockopt(IPV6_ADDRFORM) and tcp_v6_connect() change icsk->icsk_af_ops +under lock_sock(), but tcp_(get|set)sockopt() read it locklessly. To +avoid load/store tearing, we need to add READ_ONCE() and WRITE_ONCE() +for the reads and writes. + +Thanks to Eric Dumazet for providing the syzbot report: + +BUG: KCSAN: data-race in tcp_setsockopt / tcp_v6_connect + +write to 0xffff88813c624518 of 8 bytes by task 23936 on cpu 0: +tcp_v6_connect+0x5b3/0xce0 net/ipv6/tcp_ipv6.c:240 +__inet_stream_connect+0x159/0x6d0 net/ipv4/af_inet.c:660 +inet_stream_connect+0x44/0x70 net/ipv4/af_inet.c:724 +__sys_connect_file net/socket.c:1976 [inline] +__sys_connect+0x197/0x1b0 net/socket.c:1993 +__do_sys_connect net/socket.c:2003 [inline] +__se_sys_connect net/socket.c:2000 [inline] +__x64_sys_connect+0x3d/0x50 net/socket.c:2000 +do_syscall_x64 arch/x86/entry/common.c:50 [inline] +do_syscall_64+0x2b/0x70 arch/x86/entry/common.c:80 +entry_SYSCALL_64_after_hwframe+0x63/0xcd + +read to 0xffff88813c624518 of 8 bytes by task 23937 on cpu 1: +tcp_setsockopt+0x147/0x1c80 net/ipv4/tcp.c:3789 +sock_common_setsockopt+0x5d/0x70 net/core/sock.c:3585 +__sys_setsockopt+0x212/0x2b0 net/socket.c:2252 +__do_sys_setsockopt net/socket.c:2263 [inline] +__se_sys_setsockopt net/socket.c:2260 [inline] +__x64_sys_setsockopt+0x62/0x70 net/socket.c:2260 +do_syscall_x64 arch/x86/entry/common.c:50 [inline] +do_syscall_64+0x2b/0x70 arch/x86/entry/common.c:80 +entry_SYSCALL_64_after_hwframe+0x63/0xcd + +value changed: 0xffffffff8539af68 -> 0xffffffff8539aff8 + +Reported by Kernel Concurrency Sanitizer on: +CPU: 1 PID: 23937 Comm: syz-executor.5 Not tainted +6.0.0-rc4-syzkaller-00331-g4ed9c1e971b1-dirty #0 + +Hardware name: Google Google Compute Engine/Google Compute Engine, +BIOS Google 08/26/2022 + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Reported-by: syzbot +Reported-by: Eric Dumazet +Signed-off-by: Kuniyuki Iwashima +Signed-off-by: Jakub Kicinski +Signed-off-by: Kazunori Kobayashi +Signed-off-by: Greg Kroah-Hartman +--- + net/ipv4/tcp.c | 10 ++++++---- + net/ipv6/ipv6_sockglue.c | 3 ++- + net/ipv6/tcp_ipv6.c | 6 ++++-- + 3 files changed, 12 insertions(+), 7 deletions(-) + +--- a/net/ipv4/tcp.c ++++ b/net/ipv4/tcp.c +@@ -3501,8 +3501,9 @@ int tcp_setsockopt(struct sock *sk, int + const struct inet_connection_sock *icsk = inet_csk(sk); + + if (level != SOL_TCP) +- return icsk->icsk_af_ops->setsockopt(sk, level, optname, +- optval, optlen); ++ /* Paired with WRITE_ONCE() in do_ipv6_setsockopt() and tcp_v6_connect() */ ++ return READ_ONCE(icsk->icsk_af_ops)->setsockopt(sk, level, optname, ++ optval, optlen); + return do_tcp_setsockopt(sk, level, optname, optval, optlen); + } + EXPORT_SYMBOL(tcp_setsockopt); +@@ -4063,8 +4064,9 @@ int tcp_getsockopt(struct sock *sk, int + struct inet_connection_sock *icsk = inet_csk(sk); + + if (level != SOL_TCP) +- return icsk->icsk_af_ops->getsockopt(sk, level, optname, +- optval, optlen); ++ /* Paired with WRITE_ONCE() in do_ipv6_setsockopt() and tcp_v6_connect() */ ++ return READ_ONCE(icsk->icsk_af_ops)->getsockopt(sk, level, optname, ++ optval, optlen); + return do_tcp_getsockopt(sk, level, optname, optval, optlen); + } + EXPORT_SYMBOL(tcp_getsockopt); +--- a/net/ipv6/ipv6_sockglue.c ++++ b/net/ipv6/ipv6_sockglue.c +@@ -477,7 +477,8 @@ static int do_ipv6_setsockopt(struct soc + local_bh_enable(); + /* Paired with READ_ONCE(sk->sk_prot) in inet6_stream_ops */ + WRITE_ONCE(sk->sk_prot, &tcp_prot); +- icsk->icsk_af_ops = &ipv4_specific; ++ /* Paired with READ_ONCE() in tcp_(get|set)sockopt() */ ++ WRITE_ONCE(icsk->icsk_af_ops, &ipv4_specific); + sk->sk_socket->ops = &inet_stream_ops; + sk->sk_family = PF_INET; + tcp_sync_mss(sk, icsk->icsk_pmtu_cookie); +--- a/net/ipv6/tcp_ipv6.c ++++ b/net/ipv6/tcp_ipv6.c +@@ -237,7 +237,8 @@ static int tcp_v6_connect(struct sock *s + sin.sin_port = usin->sin6_port; + sin.sin_addr.s_addr = usin->sin6_addr.s6_addr32[3]; + +- icsk->icsk_af_ops = &ipv6_mapped; ++ /* Paired with READ_ONCE() in tcp_(get|set)sockopt() */ ++ WRITE_ONCE(icsk->icsk_af_ops, &ipv6_mapped); + if (sk_is_mptcp(sk)) + mptcpv6_handle_mapped(sk, true); + sk->sk_backlog_rcv = tcp_v4_do_rcv; +@@ -249,7 +250,8 @@ static int tcp_v6_connect(struct sock *s + + if (err) { + icsk->icsk_ext_hdr_len = exthdrlen; +- icsk->icsk_af_ops = &ipv6_specific; ++ /* Paired with READ_ONCE() in tcp_(get|set)sockopt() */ ++ WRITE_ONCE(icsk->icsk_af_ops, &ipv6_specific); + if (sk_is_mptcp(sk)) + mptcpv6_handle_mapped(sk, false); + sk->sk_backlog_rcv = tcp_v6_do_rcv;