From: Greg Kroah-Hartman Date: Sun, 23 Apr 2023 13:33:36 +0000 (+0200) Subject: 5.15-stable patches X-Git-Tag: v4.14.314~31 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=5ae8596bef86fea7478b66303e8daf6d986658ec;p=thirdparty%2Fkernel%2Fstable-queue.git 5.15-stable patches added patches: tcp-udp-call-inet6_destroy_sock-in-ipv6-sk-sk_destruct.patch udp-call-inet6_destroy_sock-in-setsockopt-ipv6_addrform.patch --- diff --git a/queue-5.15/series b/queue-5.15/series index 60f1f5f43ff..3e130adfa6e 100644 --- a/queue-5.15/series +++ b/queue-5.15/series @@ -55,3 +55,5 @@ purgatory-fix-disabling-debug-info.patch fuse-fix-attr-version-comparison-in-fuse_read_update_size.patch fuse-always-revalidate-rename-target-dentry.patch fuse-fix-deadlock-between-atomic-o_trunc-and-page-invalidation.patch +udp-call-inet6_destroy_sock-in-setsockopt-ipv6_addrform.patch +tcp-udp-call-inet6_destroy_sock-in-ipv6-sk-sk_destruct.patch diff --git a/queue-5.15/tcp-udp-call-inet6_destroy_sock-in-ipv6-sk-sk_destruct.patch b/queue-5.15/tcp-udp-call-inet6_destroy_sock-in-ipv6-sk-sk_destruct.patch new file mode 100644 index 00000000000..c04f15f6773 --- /dev/null +++ b/queue-5.15/tcp-udp-call-inet6_destroy_sock-in-ipv6-sk-sk_destruct.patch @@ -0,0 +1,243 @@ +From d38afeec26ed4739c640bf286c270559aab2ba5f Mon Sep 17 00:00:00 2001 +From: Kuniyuki Iwashima +Date: Thu, 6 Oct 2022 11:53:47 -0700 +Subject: tcp/udp: Call inet6_destroy_sock() in IPv6 sk->sk_destruct(). + +From: Kuniyuki Iwashima + +commit d38afeec26ed4739c640bf286c270559aab2ba5f upstream. + +Originally, inet6_sk(sk)->XXX were changed under lock_sock(), so we were +able to clean them up by calling inet6_destroy_sock() during the IPv6 -> +IPv4 conversion by IPV6_ADDRFORM. However, commit 03485f2adcde ("udpv6: +Add lockless sendmsg() support") added a lockless memory allocation path, +which could cause a memory leak: + +setsockopt(IPV6_ADDRFORM) sendmsg() ++-----------------------+ +-------+ +- do_ipv6_setsockopt(sk, ...) - udpv6_sendmsg(sk, ...) + - sockopt_lock_sock(sk) ^._ called via udpv6_prot + - lock_sock(sk) before WRITE_ONCE() + - WRITE_ONCE(sk->sk_prot, &tcp_prot) + - inet6_destroy_sock() - if (!corkreq) + - sockopt_release_sock(sk) - ip6_make_skb(sk, ...) + - release_sock(sk) ^._ lockless fast path for + the non-corking case + + - __ip6_append_data(sk, ...) + - ipv6_local_rxpmtu(sk, ...) + - xchg(&np->rxpmtu, skb) + ^._ rxpmtu is never freed. + + - goto out_no_dst; + + - lock_sock(sk) + +For now, rxpmtu is only the case, but not to miss the future change +and a similar bug fixed in commit e27326009a3d ("net: ping6: Fix +memleak in ipv6_renew_options()."), let's set a new function to IPv6 +sk->sk_destruct() and call inet6_cleanup_sock() there. Since the +conversion does not change sk->sk_destruct(), we can guarantee that +we can clean up IPv6 resources finally. + +We can now remove all inet6_destroy_sock() calls from IPv6 protocol +specific ->destroy() functions, but such changes are invasive to +backport. So they can be posted as a follow-up later for net-next. + +Fixes: 03485f2adcde ("udpv6: Add lockless sendmsg() support") +Signed-off-by: Kuniyuki Iwashima +Signed-off-by: Jakub Kicinski +Signed-off-by: Ziyang Xuan +Signed-off-by: Greg Kroah-Hartman +--- + include/net/ipv6.h | 1 + + include/net/udp.h | 2 +- + include/net/udplite.h | 8 -------- + net/ipv4/udp.c | 9 ++++++--- + net/ipv4/udplite.c | 8 ++++++++ + net/ipv6/af_inet6.c | 8 +++++++- + net/ipv6/udp.c | 15 ++++++++++++++- + net/ipv6/udp_impl.h | 1 + + net/ipv6/udplite.c | 9 ++++++++- + 9 files changed, 46 insertions(+), 15 deletions(-) + +--- a/include/net/ipv6.h ++++ b/include/net/ipv6.h +@@ -1119,6 +1119,7 @@ void ipv6_local_error(struct sock *sk, i + void ipv6_local_rxpmtu(struct sock *sk, struct flowi6 *fl6, u32 mtu); + + void inet6_cleanup_sock(struct sock *sk); ++void inet6_sock_destruct(struct sock *sk); + int inet6_release(struct socket *sock); + int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len); + int inet6_getname(struct socket *sock, struct sockaddr *uaddr, +--- a/include/net/udp.h ++++ b/include/net/udp.h +@@ -270,7 +270,7 @@ static inline bool udp_sk_bound_dev_eq(s + } + + /* net/ipv4/udp.c */ +-void udp_destruct_sock(struct sock *sk); ++void udp_destruct_common(struct sock *sk); + void skb_consume_udp(struct sock *sk, struct sk_buff *skb, int len); + int __udp_enqueue_schedule_skb(struct sock *sk, struct sk_buff *skb); + void udp_skb_destructor(struct sock *sk, struct sk_buff *skb); +--- a/include/net/udplite.h ++++ b/include/net/udplite.h +@@ -24,14 +24,6 @@ static __inline__ int udplite_getfrag(vo + return copy_from_iter_full(to, len, &msg->msg_iter) ? 0 : -EFAULT; + } + +-/* Designate sk as UDP-Lite socket */ +-static inline int udplite_sk_init(struct sock *sk) +-{ +- udp_init_sock(sk); +- udp_sk(sk)->pcflag = UDPLITE_BIT; +- return 0; +-} +- + /* + * Checksumming routines + */ +--- a/net/ipv4/udp.c ++++ b/net/ipv4/udp.c +@@ -1596,7 +1596,7 @@ drop: + } + EXPORT_SYMBOL_GPL(__udp_enqueue_schedule_skb); + +-void udp_destruct_sock(struct sock *sk) ++void udp_destruct_common(struct sock *sk) + { + /* reclaim completely the forward allocated memory */ + struct udp_sock *up = udp_sk(sk); +@@ -1609,10 +1609,14 @@ void udp_destruct_sock(struct sock *sk) + kfree_skb(skb); + } + udp_rmem_release(sk, total, 0, true); ++} ++EXPORT_SYMBOL_GPL(udp_destruct_common); + ++static void udp_destruct_sock(struct sock *sk) ++{ ++ udp_destruct_common(sk); + inet_sock_destruct(sk); + } +-EXPORT_SYMBOL_GPL(udp_destruct_sock); + + int udp_init_sock(struct sock *sk) + { +@@ -1620,7 +1624,6 @@ int udp_init_sock(struct sock *sk) + sk->sk_destruct = udp_destruct_sock; + return 0; + } +-EXPORT_SYMBOL_GPL(udp_init_sock); + + void skb_consume_udp(struct sock *sk, struct sk_buff *skb, int len) + { +--- a/net/ipv4/udplite.c ++++ b/net/ipv4/udplite.c +@@ -17,6 +17,14 @@ + struct udp_table udplite_table __read_mostly; + EXPORT_SYMBOL(udplite_table); + ++/* Designate sk as UDP-Lite socket */ ++static int udplite_sk_init(struct sock *sk) ++{ ++ udp_init_sock(sk); ++ udp_sk(sk)->pcflag = UDPLITE_BIT; ++ return 0; ++} ++ + static int udplite_rcv(struct sk_buff *skb) + { + return __udp4_lib_rcv(skb, &udplite_table, IPPROTO_UDPLITE); +--- a/net/ipv6/af_inet6.c ++++ b/net/ipv6/af_inet6.c +@@ -108,6 +108,12 @@ static __inline__ struct ipv6_pinfo *ine + return (struct ipv6_pinfo *)(((u8 *)sk) + offset); + } + ++void inet6_sock_destruct(struct sock *sk) ++{ ++ inet6_cleanup_sock(sk); ++ inet_sock_destruct(sk); ++} ++ + static int inet6_create(struct net *net, struct socket *sock, int protocol, + int kern) + { +@@ -200,7 +206,7 @@ lookup_protocol: + inet->hdrincl = 1; + } + +- sk->sk_destruct = inet_sock_destruct; ++ sk->sk_destruct = inet6_sock_destruct; + sk->sk_family = PF_INET6; + sk->sk_protocol = protocol; + +--- a/net/ipv6/udp.c ++++ b/net/ipv6/udp.c +@@ -55,6 +55,19 @@ + #include + #include "udp_impl.h" + ++static void udpv6_destruct_sock(struct sock *sk) ++{ ++ udp_destruct_common(sk); ++ inet6_sock_destruct(sk); ++} ++ ++int udpv6_init_sock(struct sock *sk) ++{ ++ skb_queue_head_init(&udp_sk(sk)->reader_queue); ++ sk->sk_destruct = udpv6_destruct_sock; ++ return 0; ++} ++ + static u32 udp6_ehashfn(const struct net *net, + const struct in6_addr *laddr, + const u16 lport, +@@ -1721,7 +1734,7 @@ struct proto udpv6_prot = { + .connect = ip6_datagram_connect, + .disconnect = udp_disconnect, + .ioctl = udp_ioctl, +- .init = udp_init_sock, ++ .init = udpv6_init_sock, + .destroy = udpv6_destroy_sock, + .setsockopt = udpv6_setsockopt, + .getsockopt = udpv6_getsockopt, +--- a/net/ipv6/udp_impl.h ++++ b/net/ipv6/udp_impl.h +@@ -12,6 +12,7 @@ int __udp6_lib_rcv(struct sk_buff *, str + int __udp6_lib_err(struct sk_buff *, struct inet6_skb_parm *, u8, u8, int, + __be32, struct udp_table *); + ++int udpv6_init_sock(struct sock *sk); + int udp_v6_get_port(struct sock *sk, unsigned short snum); + void udp_v6_rehash(struct sock *sk); + +--- a/net/ipv6/udplite.c ++++ b/net/ipv6/udplite.c +@@ -12,6 +12,13 @@ + #include + #include "udp_impl.h" + ++static int udplitev6_sk_init(struct sock *sk) ++{ ++ udpv6_init_sock(sk); ++ udp_sk(sk)->pcflag = UDPLITE_BIT; ++ return 0; ++} ++ + static int udplitev6_rcv(struct sk_buff *skb) + { + return __udp6_lib_rcv(skb, &udplite_table, IPPROTO_UDPLITE); +@@ -38,7 +45,7 @@ struct proto udplitev6_prot = { + .connect = ip6_datagram_connect, + .disconnect = udp_disconnect, + .ioctl = udp_ioctl, +- .init = udplite_sk_init, ++ .init = udplitev6_sk_init, + .destroy = udpv6_destroy_sock, + .setsockopt = udpv6_setsockopt, + .getsockopt = udpv6_getsockopt, diff --git a/queue-5.15/udp-call-inet6_destroy_sock-in-setsockopt-ipv6_addrform.patch b/queue-5.15/udp-call-inet6_destroy_sock-in-setsockopt-ipv6_addrform.patch new file mode 100644 index 00000000000..0320a805ed5 --- /dev/null +++ b/queue-5.15/udp-call-inet6_destroy_sock-in-setsockopt-ipv6_addrform.patch @@ -0,0 +1,106 @@ +From 21985f43376cee092702d6cb963ff97a9d2ede68 Mon Sep 17 00:00:00 2001 +From: Kuniyuki Iwashima +Date: Thu, 6 Oct 2022 11:53:46 -0700 +Subject: udp: Call inet6_destroy_sock() in setsockopt(IPV6_ADDRFORM). + +From: Kuniyuki Iwashima + +commit 21985f43376cee092702d6cb963ff97a9d2ede68 upstream. + +Commit 4b340ae20d0e ("IPv6: Complete IPV6_DONTFRAG support") forgot +to add a change to free inet6_sk(sk)->rxpmtu while converting an IPv6 +socket into IPv4 with IPV6_ADDRFORM. After conversion, sk_prot is +changed to udp_prot and ->destroy() never cleans it up, resulting in +a memory leak. + +This is due to the discrepancy between inet6_destroy_sock() and +IPV6_ADDRFORM, so let's call inet6_destroy_sock() from IPV6_ADDRFORM +to remove the difference. + +However, this is not enough for now because rxpmtu can be changed +without lock_sock() after commit 03485f2adcde ("udpv6: Add lockless +sendmsg() support"). We will fix this case in the following patch. + +Note we will rename inet6_destroy_sock() to inet6_cleanup_sock() and +remove unnecessary inet6_destroy_sock() calls in sk_prot->destroy() +in the future. + +Fixes: 4b340ae20d0e ("IPv6: Complete IPV6_DONTFRAG support") +Signed-off-by: Kuniyuki Iwashima +Signed-off-by: Jakub Kicinski +Signed-off-by: Ziyang Xuan +Signed-off-by: Greg Kroah-Hartman +--- + include/net/ipv6.h | 1 + + net/ipv6/af_inet6.c | 6 ++++++ + net/ipv6/ipv6_sockglue.c | 20 ++++++++------------ + 3 files changed, 15 insertions(+), 12 deletions(-) + +--- a/include/net/ipv6.h ++++ b/include/net/ipv6.h +@@ -1118,6 +1118,7 @@ void ipv6_icmp_error(struct sock *sk, st + void ipv6_local_error(struct sock *sk, int err, struct flowi6 *fl6, u32 info); + void ipv6_local_rxpmtu(struct sock *sk, struct flowi6 *fl6, u32 mtu); + ++void inet6_cleanup_sock(struct sock *sk); + int inet6_release(struct socket *sock); + int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len); + int inet6_getname(struct socket *sock, struct sockaddr *uaddr, +--- a/net/ipv6/af_inet6.c ++++ b/net/ipv6/af_inet6.c +@@ -507,6 +507,12 @@ void inet6_destroy_sock(struct sock *sk) + } + EXPORT_SYMBOL_GPL(inet6_destroy_sock); + ++void inet6_cleanup_sock(struct sock *sk) ++{ ++ inet6_destroy_sock(sk); ++} ++EXPORT_SYMBOL_GPL(inet6_cleanup_sock); ++ + /* + * This does both peername and sockname. + */ +--- a/net/ipv6/ipv6_sockglue.c ++++ b/net/ipv6/ipv6_sockglue.c +@@ -429,9 +429,6 @@ static int do_ipv6_setsockopt(struct soc + if (optlen < sizeof(int)) + goto e_inval; + if (val == PF_INET) { +- struct ipv6_txoptions *opt; +- struct sk_buff *pktopt; +- + if (sk->sk_type == SOCK_RAW) + break; + +@@ -462,7 +459,6 @@ static int do_ipv6_setsockopt(struct soc + break; + } + +- fl6_free_socklist(sk); + __ipv6_sock_mc_close(sk); + __ipv6_sock_ac_close(sk); + +@@ -497,14 +493,14 @@ static int do_ipv6_setsockopt(struct soc + sk->sk_socket->ops = &inet_dgram_ops; + sk->sk_family = PF_INET; + } +- opt = xchg((__force struct ipv6_txoptions **)&np->opt, +- NULL); +- if (opt) { +- atomic_sub(opt->tot_len, &sk->sk_omem_alloc); +- txopt_put(opt); +- } +- pktopt = xchg(&np->pktoptions, NULL); +- kfree_skb(pktopt); ++ ++ /* Disable all options not to allocate memory anymore, ++ * but there is still a race. See the lockless path ++ * in udpv6_sendmsg() and ipv6_local_rxpmtu(). ++ */ ++ np->rxopt.all = 0; ++ ++ inet6_cleanup_sock(sk); + + /* + * ... and add it to the refcnt debug socks count