Skip to content

Commit 21985f4

Browse files
q2venkuba-moo
authored andcommitted
udp: Call inet6_destroy_sock() in setsockopt(IPV6_ADDRFORM).
Commit 4b340ae ("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 03485f2 ("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: 4b340ae ("IPv6: Complete IPV6_DONTFRAG support") Signed-off-by: Kuniyuki Iwashima <[email protected]> Signed-off-by: Jakub Kicinski <[email protected]>
1 parent 3c52c6b commit 21985f4

File tree

3 files changed

+15
-12
lines changed

3 files changed

+15
-12
lines changed

include/net/ipv6.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1182,6 +1182,7 @@ void ipv6_icmp_error(struct sock *sk, struct sk_buff *skb, int err, __be16 port,
11821182
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

1185+
void inet6_cleanup_sock(struct sock *sk);
11851186
int inet6_release(struct socket *sock);
11861187
int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len);
11871188
int inet6_getname(struct socket *sock, struct sockaddr *uaddr,

net/ipv6/af_inet6.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -510,6 +510,12 @@ void inet6_destroy_sock(struct sock *sk)
510510
}
511511
EXPORT_SYMBOL_GPL(inet6_destroy_sock);
512512

513+
void inet6_cleanup_sock(struct sock *sk)
514+
{
515+
inet6_destroy_sock(sk);
516+
}
517+
EXPORT_SYMBOL_GPL(inet6_cleanup_sock);
518+
513519
/*
514520
* This does both peername and sockname.
515521
*/

net/ipv6/ipv6_sockglue.c

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -431,9 +431,6 @@ int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
431431
if (optlen < sizeof(int))
432432
goto e_inval;
433433
if (val == PF_INET) {
434-
struct ipv6_txoptions *opt;
435-
struct sk_buff *pktopt;
436-
437434
if (sk->sk_type == SOCK_RAW)
438435
break;
439436

@@ -464,7 +461,6 @@ int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
464461
break;
465462
}
466463

467-
fl6_free_socklist(sk);
468464
__ipv6_sock_mc_close(sk);
469465
__ipv6_sock_ac_close(sk);
470466

@@ -501,14 +497,14 @@ int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
501497
sk->sk_socket->ops = &inet_dgram_ops;
502498
sk->sk_family = PF_INET;
503499
}
504-
opt = xchg((__force struct ipv6_txoptions **)&np->opt,
505-
NULL);
506-
if (opt) {
507-
atomic_sub(opt->tot_len, &sk->sk_omem_alloc);
508-
txopt_put(opt);
509-
}
510-
pktopt = xchg(&np->pktoptions, NULL);
511-
kfree_skb(pktopt);
500+
501+
/* Disable all options not to allocate memory anymore,
502+
* but there is still a race. See the lockless path
503+
* in udpv6_sendmsg() and ipv6_local_rxpmtu().
504+
*/
505+
np->rxopt.all = 0;
506+
507+
inet6_cleanup_sock(sk);
512508

513509
/*
514510
* ... and add it to the refcnt debug socks count

0 commit comments

Comments
 (0)