Skip to content

Commit d38afee

Browse files
q2venkuba-moo
authored andcommitted
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 03485f2 ("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 e273260 ("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: 03485f2 ("udpv6: Add lockless sendmsg() support") Signed-off-by: Kuniyuki Iwashima <[email protected]> Signed-off-by: Jakub Kicinski <[email protected]>
1 parent 21985f4 commit d38afee

File tree

9 files changed

+46
-15
lines changed

9 files changed

+46
-15
lines changed

include/net/ipv6.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1183,6 +1183,7 @@ void ipv6_local_error(struct sock *sk, int err, struct flowi6 *fl6, u32 info);
11831183
void ipv6_local_rxpmtu(struct sock *sk, struct flowi6 *fl6, u32 mtu);
11841184

11851185
void inet6_cleanup_sock(struct sock *sk);
1186+
void inet6_sock_destruct(struct sock *sk);
11861187
int inet6_release(struct socket *sock);
11871188
int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len);
11881189
int inet6_getname(struct socket *sock, struct sockaddr *uaddr,

include/net/udp.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,7 @@ static inline bool udp_sk_bound_dev_eq(struct net *net, int bound_dev_if,
247247
}
248248

249249
/* net/ipv4/udp.c */
250-
void udp_destruct_sock(struct sock *sk);
250+
void udp_destruct_common(struct sock *sk);
251251
void skb_consume_udp(struct sock *sk, struct sk_buff *skb, int len);
252252
int __udp_enqueue_schedule_skb(struct sock *sk, struct sk_buff *skb);
253253
void udp_skb_destructor(struct sock *sk, struct sk_buff *skb);

include/net/udplite.h

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,6 @@ static __inline__ int udplite_getfrag(void *from, char *to, int offset,
2525
return copy_from_iter_full(to, len, &msg->msg_iter) ? 0 : -EFAULT;
2626
}
2727

28-
/* Designate sk as UDP-Lite socket */
29-
static inline int udplite_sk_init(struct sock *sk)
30-
{
31-
udp_init_sock(sk);
32-
udp_sk(sk)->pcflag = UDPLITE_BIT;
33-
return 0;
34-
}
35-
3628
/*
3729
* Checksumming routines
3830
*/

net/ipv4/udp.c

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1598,7 +1598,7 @@ int __udp_enqueue_schedule_skb(struct sock *sk, struct sk_buff *skb)
15981598
}
15991599
EXPORT_SYMBOL_GPL(__udp_enqueue_schedule_skb);
16001600

1601-
void udp_destruct_sock(struct sock *sk)
1601+
void udp_destruct_common(struct sock *sk)
16021602
{
16031603
/* reclaim completely the forward allocated memory */
16041604
struct udp_sock *up = udp_sk(sk);
@@ -1611,18 +1611,21 @@ void udp_destruct_sock(struct sock *sk)
16111611
kfree_skb(skb);
16121612
}
16131613
udp_rmem_release(sk, total, 0, true);
1614+
}
1615+
EXPORT_SYMBOL_GPL(udp_destruct_common);
16141616

1617+
static void udp_destruct_sock(struct sock *sk)
1618+
{
1619+
udp_destruct_common(sk);
16151620
inet_sock_destruct(sk);
16161621
}
1617-
EXPORT_SYMBOL_GPL(udp_destruct_sock);
16181622

16191623
int udp_init_sock(struct sock *sk)
16201624
{
16211625
skb_queue_head_init(&udp_sk(sk)->reader_queue);
16221626
sk->sk_destruct = udp_destruct_sock;
16231627
return 0;
16241628
}
1625-
EXPORT_SYMBOL_GPL(udp_init_sock);
16261629

16271630
void skb_consume_udp(struct sock *sk, struct sk_buff *skb, int len)
16281631
{

net/ipv4/udplite.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,14 @@
1717
struct udp_table udplite_table __read_mostly;
1818
EXPORT_SYMBOL(udplite_table);
1919

20+
/* Designate sk as UDP-Lite socket */
21+
static int udplite_sk_init(struct sock *sk)
22+
{
23+
udp_init_sock(sk);
24+
udp_sk(sk)->pcflag = UDPLITE_BIT;
25+
return 0;
26+
}
27+
2028
static int udplite_rcv(struct sk_buff *skb)
2129
{
2230
return __udp4_lib_rcv(skb, &udplite_table, IPPROTO_UDPLITE);

net/ipv6/af_inet6.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,12 @@ static __inline__ struct ipv6_pinfo *inet6_sk_generic(struct sock *sk)
109109
return (struct ipv6_pinfo *)(((u8 *)sk) + offset);
110110
}
111111

112+
void inet6_sock_destruct(struct sock *sk)
113+
{
114+
inet6_cleanup_sock(sk);
115+
inet_sock_destruct(sk);
116+
}
117+
112118
static int inet6_create(struct net *net, struct socket *sock, int protocol,
113119
int kern)
114120
{
@@ -201,7 +207,7 @@ static int inet6_create(struct net *net, struct socket *sock, int protocol,
201207
inet->hdrincl = 1;
202208
}
203209

204-
sk->sk_destruct = inet_sock_destruct;
210+
sk->sk_destruct = inet6_sock_destruct;
205211
sk->sk_family = PF_INET6;
206212
sk->sk_protocol = protocol;
207213

net/ipv6/udp.c

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,19 @@
5656
#include <trace/events/skb.h>
5757
#include "udp_impl.h"
5858

59+
static void udpv6_destruct_sock(struct sock *sk)
60+
{
61+
udp_destruct_common(sk);
62+
inet6_sock_destruct(sk);
63+
}
64+
65+
int udpv6_init_sock(struct sock *sk)
66+
{
67+
skb_queue_head_init(&udp_sk(sk)->reader_queue);
68+
sk->sk_destruct = udpv6_destruct_sock;
69+
return 0;
70+
}
71+
5972
static u32 udp6_ehashfn(const struct net *net,
6073
const struct in6_addr *laddr,
6174
const u16 lport,
@@ -1733,7 +1746,7 @@ struct proto udpv6_prot = {
17331746
.connect = ip6_datagram_connect,
17341747
.disconnect = udp_disconnect,
17351748
.ioctl = udp_ioctl,
1736-
.init = udp_init_sock,
1749+
.init = udpv6_init_sock,
17371750
.destroy = udpv6_destroy_sock,
17381751
.setsockopt = udpv6_setsockopt,
17391752
.getsockopt = udpv6_getsockopt,

net/ipv6/udp_impl.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ int __udp6_lib_rcv(struct sk_buff *, struct udp_table *, int);
1212
int __udp6_lib_err(struct sk_buff *, struct inet6_skb_parm *, u8, u8, int,
1313
__be32, struct udp_table *);
1414

15+
int udpv6_init_sock(struct sock *sk);
1516
int udp_v6_get_port(struct sock *sk, unsigned short snum);
1617
void udp_v6_rehash(struct sock *sk);
1718

net/ipv6/udplite.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,13 @@
1212
#include <linux/proc_fs.h>
1313
#include "udp_impl.h"
1414

15+
static int udplitev6_sk_init(struct sock *sk)
16+
{
17+
udpv6_init_sock(sk);
18+
udp_sk(sk)->pcflag = UDPLITE_BIT;
19+
return 0;
20+
}
21+
1522
static int udplitev6_rcv(struct sk_buff *skb)
1623
{
1724
return __udp6_lib_rcv(skb, &udplite_table, IPPROTO_UDPLITE);
@@ -38,7 +45,7 @@ struct proto udplitev6_prot = {
3845
.connect = ip6_datagram_connect,
3946
.disconnect = udp_disconnect,
4047
.ioctl = udp_ioctl,
41-
.init = udplite_sk_init,
48+
.init = udplitev6_sk_init,
4249
.destroy = udpv6_destroy_sock,
4350
.setsockopt = udpv6_setsockopt,
4451
.getsockopt = udpv6_getsockopt,

0 commit comments

Comments
 (0)