2019-05-27 09:55:01 +03:00
// SPDX-License-Identifier: GPL-2.0-or-later
2006-11-27 22:10:57 +03:00
/*
* UDPLITEv6 An implementation of the UDP - Lite protocol over IPv6 .
* See also net / ipv4 / udplite . c
*
* Authors : Gerrit Renker < gerrit @ erg . abdn . ac . uk >
*
* Changes :
* Fixes :
*/
2023-06-14 22:47:04 +03:00
# define pr_fmt(fmt) "UDPLite6: " fmt
2011-07-15 19:47:34 +04:00
# include <linux/export.h>
2018-04-10 22:31:50 +03:00
# include <linux/proc_fs.h>
2006-11-27 22:10:57 +03:00
# include "udp_impl.h"
tcp/udp: Call inet6_destroy_sock() in IPv6 sk->sk_destruct().
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 <kuniyu@amazon.com>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2022-10-06 21:53:47 +03:00
static int udplitev6_sk_init ( struct sock * sk )
{
udpv6_init_sock ( sk ) ;
2023-06-14 22:47:04 +03:00
pr_warn_once ( " UDP-Lite is deprecated and scheduled to be removed in 2025, "
" please contact the netdev mailing list \n " ) ;
tcp/udp: Call inet6_destroy_sock() in IPv6 sk->sk_destruct().
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 <kuniyu@amazon.com>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2022-10-06 21:53:47 +03:00
return 0 ;
}
2007-10-15 23:50:28 +04:00
static int udplitev6_rcv ( struct sk_buff * skb )
2006-11-27 22:10:57 +03:00
{
2008-10-29 11:41:45 +03:00
return __udp6_lib_rcv ( skb , & udplite_table , IPPROTO_UDPLITE ) ;
2006-11-27 22:10:57 +03:00
}
2018-11-08 14:19:21 +03:00
static int udplitev6_err ( struct sk_buff * skb ,
2006-12-01 04:22:29 +03:00
struct inet6_skb_parm * opt ,
2009-06-23 15:31:07 +04:00
u8 type , u8 code , int offset , __be32 info )
2006-11-27 22:10:57 +03:00
{
2018-11-08 14:19:21 +03:00
return __udp6_lib_err ( skb , opt , type , code , offset , info ,
& udplite_table ) ;
2006-11-27 22:10:57 +03:00
}
2009-09-14 16:22:28 +04:00
static const struct inet6_protocol udplitev6_protocol = {
2006-11-27 22:10:57 +03:00
. handler = udplitev6_rcv ,
. err_handler = udplitev6_err ,
. flags = INET6_PROTO_NOPOLICY | INET6_PROTO_FINAL ,
} ;
struct proto udplitev6_prot = {
. name = " UDPLITEv6 " ,
. owner = THIS_MODULE ,
. close = udp_lib_close ,
. connect = ip6_datagram_connect ,
. disconnect = udp_disconnect ,
. ioctl = udp_ioctl ,
tcp/udp: Call inet6_destroy_sock() in IPv6 sk->sk_destruct().
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 <kuniyu@amazon.com>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2022-10-06 21:53:47 +03:00
. init = udplitev6_sk_init ,
2006-11-27 22:10:57 +03:00
. destroy = udpv6_destroy_sock ,
. setsockopt = udpv6_setsockopt ,
. getsockopt = udpv6_getsockopt ,
. sendmsg = udpv6_sendmsg ,
. recvmsg = udpv6_recvmsg ,
. hash = udp_lib_hash ,
. unhash = udp_lib_unhash ,
2019-01-16 19:17:45 +03:00
. rehash = udp_v6_rehash ,
2008-03-23 02:51:21 +03:00
. get_port = udp_v6_get_port ,
2022-06-09 09:34:08 +03:00
2016-11-15 18:37:53 +03:00
. memory_allocated = & udp_memory_allocated ,
2022-06-09 09:34:08 +03:00
. per_cpu_fw_alloc = & udp_memory_per_cpu_fw_alloc ,
2016-11-15 18:37:53 +03:00
. sysctl_mem = sysctl_udp_mem ,
2023-05-23 19:33:05 +03:00
. sysctl_wmem_offset = offsetof ( struct net , ipv4 . sysctl_udp_wmem_min ) ,
. sysctl_rmem_offset = offsetof ( struct net , ipv4 . sysctl_udp_rmem_min ) ,
2006-11-27 22:10:57 +03:00
. obj_size = sizeof ( struct udp6_sock ) ,
2023-07-20 14:09:01 +03:00
. ipv6_pinfo_offset = offsetof ( struct udp6_sock , inet6 ) ,
2008-10-29 11:41:45 +03:00
. h . udp_table = & udplite_table ,
2006-11-27 22:10:57 +03:00
} ;
static struct inet_protosw udplite6_protosw = {
. type = SOCK_DGRAM ,
. protocol = IPPROTO_UDPLITE ,
. prot = & udplitev6_prot ,
. ops = & inet6_dgram_ops ,
. flags = INET_PROTOSW_PERMANENT ,
} ;
2007-12-11 13:25:35 +03:00
int __init udplitev6_init ( void )
2006-11-27 22:10:57 +03:00
{
2007-12-11 13:25:35 +03:00
int ret ;
2006-11-27 22:10:57 +03:00
2007-12-11 13:25:35 +03:00
ret = inet6_add_protocol ( & udplitev6_protocol , IPPROTO_UDPLITE ) ;
if ( ret )
goto out ;
ret = inet6_register_protosw ( & udplite6_protosw ) ;
if ( ret )
goto out_udplitev6_protocol ;
out :
return ret ;
out_udplitev6_protocol :
inet6_del_protocol ( & udplitev6_protocol , IPPROTO_UDPLITE ) ;
goto out ;
}
2007-12-13 16:34:58 +03:00
void udplitev6_exit ( void )
2007-12-11 13:25:35 +03:00
{
inet6_unregister_protosw ( & udplite6_protosw ) ;
inet6_del_protocol ( & udplitev6_protocol , IPPROTO_UDPLITE ) ;
2006-11-27 22:10:57 +03:00
}
# ifdef CONFIG_PROC_FS
static struct udp_seq_afinfo udplite6_seq_afinfo = {
. family = AF_INET6 ,
2008-10-29 11:41:45 +03:00
. udp_table = & udplite_table ,
2006-11-27 22:10:57 +03:00
} ;
2010-01-17 06:35:32 +03:00
static int __net_init udplite6_proc_init_net ( struct net * net )
2008-03-25 00:56:57 +03:00
{
2018-04-10 20:42:55 +03:00
if ( ! proc_create_net_data ( " udplite6 " , 0444 , net - > proc_net ,
& udp6_seq_ops , sizeof ( struct udp_iter_state ) ,
& udplite6_seq_afinfo ) )
2018-04-10 22:31:50 +03:00
return - ENOMEM ;
return 0 ;
2008-03-25 00:56:57 +03:00
}
2010-01-17 06:35:32 +03:00
static void __net_exit udplite6_proc_exit_net ( struct net * net )
2008-03-25 00:56:57 +03:00
{
2018-04-10 22:31:50 +03:00
remove_proc_entry ( " udplite6 " , net - > proc_net ) ;
2008-03-25 00:56:57 +03:00
}
static struct pernet_operations udplite6_net_ops = {
. init = udplite6_proc_init_net ,
. exit = udplite6_proc_exit_net ,
} ;
2006-11-27 22:10:57 +03:00
int __init udplite6_proc_init ( void )
{
2008-03-25 00:56:57 +03:00
return register_pernet_subsys ( & udplite6_net_ops ) ;
2006-11-27 22:10:57 +03:00
}
void udplite6_proc_exit ( void )
{
2008-03-25 00:56:57 +03:00
unregister_pernet_subsys ( & udplite6_net_ops ) ;
2006-11-27 22:10:57 +03:00
}
# endif